Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
LINQ的FirstOrDefault()与Lambda的FirstOrDefault()之间的比较?_Linq_.net 3.5 - Fatal编程技术网

LINQ的FirstOrDefault()与Lambda的FirstOrDefault()之间的比较?

LINQ的FirstOrDefault()与Lambda的FirstOrDefault()之间的比较?,linq,.net-3.5,Linq,.net 3.5,我有点好奇,在FirstOrDefault中,哪一种被认为是“最佳实践” 我已经看到了这个问题,它与我的问题相似,但距离不够近,无法回答我的问题 以下哪项是“更好的代码”?为什么呢? var foos = GetMyEnumerableFoos(); var foo1 = (from f in foos where f.Bar == "spider monkey" select f).FirstOrDefault(); /* OR */ var foo2 = foos.

我有点好奇,在FirstOrDefault中,哪一种被认为是“最佳实践”

我已经看到了这个问题,它与我的问题相似,但距离不够近,无法回答我的问题

以下哪项是“更好的代码”?为什么呢?

var foos = GetMyEnumerableFoos();

var foo1 = (from f in foos
     where f.Bar == "spider monkey"
     select f).FirstOrDefault();

/* OR */

var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey");
我倾向于后者,因为在我看来,它使代码更清晰。但我很好奇,在那里发生的事情的技术“勇气”是否比另一种方式更有效。如果使用不同类型的IEnumerable,这种情况会发生变化吗?比如数据表、字符串数组或LINQ对象

==========编辑==========

假设Jon Skeet的帖子是正确的,我去反射器看看Where和FirstOrDefault是什么样子,下面是我的想法:

如果是foos.Where(f=>f.Bar==“蜘蛛猴”).FirstOrDefault()

公共静态IEnumerable Where(此IEnumerable源,Func谓词)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
if(谓词==null)
{
抛出错误。ArgumentNull(“谓词”);
}
if(源是迭代器)
{
返回((迭代器)源)。其中(谓词);
}
如果(源为TSource[])
{
返回新的whererrayiterator((TSource[])源,谓词;
}
如果(来源是列表)
{
返回新的WhereListIterator((列表)源,谓词);
}
返回新的WhereEnumerableIterator(源,谓词);
}
这将有助于:

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    IList<TSource> list = source as IList<TSource>;
    if (list != null)
    {
        if (list.Count > 0)
        {
            return list[0];
        }
    }
    else
    {
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            if (enumerator.MoveNext())
            {
                return enumerator.Current;
            }
        }
    }
    return default(TSource);
}
publicstatictsourcefirstOrdefault(此IEnumerable源代码)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
IList list=源作为IList;
如果(列表!=null)
{
如果(list.Count>0)
{
返回列表[0];
}
}
其他的
{
使用(IEnumerator enumerator=source.GetEnumerator())
{
if(枚举数.MoveNext())
{
返回枚举数.Current;
}
}
}
返回默认值(TSource);
}
对于foos.FirstOrDefault(f=>f.Bar==“蜘蛛猴”)

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource local in source)
    {
        if (predicate(local))
        {
            return local;
        }
    }
    return default(TSource);
}
public static TSource FirstOrDefault(此IEnumerable源,Func谓词)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
if(谓词==null)
{
抛出错误。ArgumentNull(“谓词”);
}
foreach(源中的TSource本地)
{
if(谓词(局部))
{
返回本地;
}
}
返回默认值(TSource);
}
看到这一点,我仍然有点困惑,对某些对象类型使用适当的迭代器会提高效率吗?还是跳过所有这些,直接开始循环测试更有效?我的直觉再次告诉我这是后者。

好吧,“选择”部分无论如何都会被编译器删除,所以你真的在比较:

foo.Where(f => f.Bar == "spider monkey")
   .FirstOrDefault()
vs


无论如何,我怀疑它是否会对LINQ到对象的效率产生重大影响。我个人会自己使用后一个版本。。。除非我想在别处重用查询的过滤部分。

我更喜欢后者,因为后者更简洁

就效率而言,我怀疑你是否能找到这两种方法之间的实质性区别。他们的行为几乎相同,尽管在实践中他们的工作略有不同


最大的区别是第一个创建了一个新的
IEnumerable
实例,然后为第一个元素遍历该实例。在后一种情况下,对与谓词匹配的第一个值遍历现有的
IEnumerable
实例。同样,这也不太可能被注意到。

第二个版本会更有效率

第一版

var foo1 = (from f in foos
     where f.Bar == "spider monkey"
     select f).FirstOrDefault();
将始终循环所有项,创建匹配项的新集合

第二版

var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey");

将仅循环遍历项目,直到找到匹配项并返回

那很有趣。在你发帖之后,我做了更多的挖掘,只是想看看你提到的三种方法中发生了什么。我把我的发现贴在上面。。。这当然有助于回答我的问题。我还没有检查,但我假设
Where
return
都不会导致
IList
,因此最后两个循环实际上是相同的:
MoveNext
将从
Where
调用
谓词,Where作为
FirstOrDefault(谓词)
call显式调用它。因此,
Where
版本的每个
false
(以及最后的
true
,如果存在)
谓词都有一个额外的调用。实际上,如果您在LINQ中添加断点,您将看到这一点。。。但它只执行该LINQ语句一次。您甚至可以使用LINQ语句访问由LINQ语句创建的IEnumerables,如果调用FirstOrDefault,它仍然只会对它们进行一次检查。不过,别担心,我以前也这么想语句“将始终循环所有项,创建匹配项的新集合”在两个方面为false。首先,如果没有“蜘蛛猴”,它将只遍历
foos
中的所有项目,否则它将在命中第一个“蜘蛛猴”时停止。其次,它不会创建匹配项的集合,而是返回第一个。我认为@phdesign因为括号的存在而感到困惑——他假设里面的所有内容都是先执行的(因为括号通常就是这样做的)。但是,该规则在本例中不适用,它们仅作为分组构造存在。
var foo1 = (from f in foos
     where f.Bar == "spider monkey"
     select f).FirstOrDefault();
var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey");