代码之家  ›  专栏  ›  技术社区  ›  Ben Lesh

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

  •  14
  • Ben Lesh  · 技术社区  · 15 年前

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

    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");
    

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

    假设Jon Skeet的帖子是正确的,我去反射器看看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);
    }
    

    这将有助于:

    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);
    }
    

    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);
    }
    

    看到这一点,我仍然有点困惑,对某些对象类型使用适当的迭代器会提高效率吗?还是跳过所有这些,直接开始循环测试更有效?我的直觉再次告诉我是后者。

    3 回复  |  直到 15 年前
        1
  •  18
  •   Jon Skeet    15 年前

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

    vs

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

    我怀疑这会有什么好处 重要的 无论如何,LINQ中的效率差异会影响到对象。我个人会自己使用后一个版本。。。除非我想在别处重用查询的过滤部分。

        2
  •  4
  •   JaredPar    15 年前

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

    最大的区别是第一个创建了一个新的 IEnumerable<T> IEnumerable<T> 为匹配谓词的第一个值遍历实例。同样,这也不太可能被注意到。

        3
  •  -1
  •   phdesign    14 年前

    第一版

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

    将始终循环所有项,创建匹配项的新集合。

    第二版

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

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