FirstOrDefault()关闭LINQ与FirstOrDefault()的Lambda?

Ben*_*esh 14 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(f => f.Bar == "spider monkey");
Run Code Online (Sandbox Code Playgroud)

我倾向于后者,作为IMO,它使代码更清晰.但我很好奇,对于那些正在发生的事情的技术"胆量"是否更有效率.如果您使用不同类型的IEnumerables,这会改变吗?像DataTables或字符串数​​组或LINQ对象?

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

假设Jon Skeet的帖子是正确的,我去了Reflector看看Where和FirstOrDefault的样子,这就是我想出的:

在foos.Where(f => f.Bar =="蜘蛛猴")的情况下.FirstOrDefault()

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    if (source is Iterator<TSource>)
    {
        return ((Iterator<TSource>) source).Where(predicate);
    }
    if (source is TSource[])
    {
        return new WhereArrayIterator<TSource>((TSource[]) source, predicate);
    }
    if (source is List<TSource>)
    {
        return new WhereListIterator<TSource>((List<TSource>) source, predicate);
    }
    return new WhereEnumerableIterator<TSource>(source, predicate);
}
Run Code Online (Sandbox Code Playgroud)

这将进入:

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);
}
Run Code Online (Sandbox Code Playgroud)

在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);
}
Run Code Online (Sandbox Code Playgroud)

看着这仍然让我有点困惑,通过对某些对象类型使用适当的迭代器会增加效率吗?或者是否更有效地跳过所有这些并开始循环并测试?我的直觉再次告诉我,这是后者.

Jon*_*eet 18

那么,编译器会删除"select"部分,所以你真的在比较:

foo.Where(f => f.Bar == "spider monkey")
   .FirstOrDefault()
Run Code Online (Sandbox Code Playgroud)

VS

foo.FirstOrDefault(f => f.Bar == "spider monkey")
Run Code Online (Sandbox Code Playgroud)

我怀疑它无论如何都会对LINQ to Objects中的效率产生任何重大影响.我本人亲自使用后一版本...除非我想在其他地方重用查询的过滤部分.