First()和Find()之间的区别

所以我知道Find()只是一个List<T>方法,而First()是任何IEnumerable<T>的扩展。 我也知道如果没有parameter passing, First()会返回第一个元素,而Find()会抛出一个exception。 最后,我知道如果找不到元素, First()将抛出exception,而Find()将返回该types的默认值。

我希望能澄清我实际上在问什么。 这是一个计算机科学问题,在计算层面处理这些方法。 我已经明白, IEnumerable<T>扩展并不总是如人们所期望的那样运行。 所以这里是Q,我的意思是从“接近金属”的angular度来看: Find()First()之间有什么区别?

这里有一些代码提供了基本的假设来操作这个问题。

 var l = new List<int> { 1, 2, 3, 4, 5 }; var x = l.First(i => i == 3); var y = l.Find(i => i == 3); 

First()Find()如何在上面的代码中发现它们的值之间有什么实际的计算差异?

注意:现在让我们忽略像AsParallel()AsQueryable()这样的东西。

这是List<T>.Find (来自Reflector)的代码:

 public T Find(Predicate<T> match) { if (match == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } for (int i = 0; i < this._size; i++) { if (match(this._items[i])) { return this._items[i]; } } return default(T); } 

这里是Enumerable.First

 public static TSource First<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; } } throw Error.NoMatch(); } 

所以这两种方法的工作方式大致相同:迭代所有项目,直到find与谓词相匹配的项目。 唯一明显的区别是Find使用for循环,因为它已经知道元素的数量,而First使用foreach循环,因为它不知道它。

First会发现一个exception,但它找不到任何东西,然而FirstOrDefaultFind完全一样(除了它是如何遍历元素的)。

由于List<>没有以任何方式编入索引,所以必须通过所有的值才能find一个特定的值。 因此,与通过枚举(除了创build一个可枚举的帮助程序对象实例之外)遍历列表相比,它没有什么区别。

这就是说,请记住Find函数的创build方式比第First扩展方法(Framework V2.0 vs V3.5)早,我怀疑如果List<>类已经实现了同时作为扩展方法。

如果在枚举器而不是列表上使用Find,将会有潜在的性能成本,因为枚举器可能不需要获取整个列表来满足谓词呢? 相反,如果你已经有一个列表,然后查找会更好。

顺便说一句Find相当于FirstOrDefault()不是First() 。 因为如果First()谓词不满足任何列表元素,你将会得到一个exception。 在这里,返回一个dotpeek ,另一个伟大的免费reflection器replace一些ReSharperfunction

这里为Enumerable.First(...)Enumerable.FirstOrDefault(...)扩展方法:

  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 element in source) { if (predicate(element)) return element; } return default(TSource); } public static TSource First<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 element in source) { if (predicate(element)) return element; } throw Error.NoMatch(); } 

这里是List <>。Find:

 /// <summary> /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire <see cref="T:System.Collections.Generic.List`1"/>. /// </summary> /// /// <returns> /// The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type <paramref name="T"/>. /// </returns> /// <param name="match">The <see cref="T:System.Predicate`1"/> delegate that defines the conditions of the element to search for.</param><exception cref="T:System.ArgumentNullException"><paramref name="match"/> is null.</exception> [__DynamicallyInvokable] public T Find(Predicate<T> match) { if (match == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); for (int index = 0; index < this._size; ++index) { if (match(this._items[index])) return this._items[index]; } return default (T); }