我能够模仿你的结果,所以我反编译了你的程序,两者之间存在差异Find
and FirstOrDefault
.
首先是编译后的程序。我将你的数据对象设为匿名数据项只是为了编译
List<\u003C\u003Ef__AnonymousType0<string>> source = Enumerable.ToList(Enumerable.Select(Enumerable.Range(0, 1000000), i =>
{
var local_0 = new
{
Name = Guid.NewGuid().ToString()
};
return local_0;
}));
source.Insert(999000, new
{
Name = diana
});
stopwatch.Restart();
Enumerable.FirstOrDefault(source, c => c.Name == diana);
stopwatch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Linq.Enumerable.FirstOrDefault().", (object) stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
source.Find(c => c.Name == diana);
stopwatch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Collections.Generic.List<T>.Find().", (object) stopwatch.ElapsedMilliseconds);
这里要注意的关键是FirstOrDefault
被召唤Enumerable
然而Find
作为源列表上的方法被调用。
那么,find 在做什么呢?这是反编译后的Find
method
private T[] _items;
[__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);
}
因此,它迭代一个有意义的项目数组,因为列表是数组的包装器。
然而,FirstOrDefault
,在Enumerable
类、用途foreach
迭代项目。这使用列表的迭代器并移动到下一个。我认为你看到的是迭代器的开销
[__DynamicallyInvokable]
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 source1 in source)
{
if (predicate(source1))
return source1;
}
return default (TSource);
}
Foreach 只是句法糖关于使用可枚举模式。看看这张图片
.
我单击 foreach 来查看它在做什么,您可以看到 dotpeek 想要带我到 enumerator/current/next 实现,这是有意义的。
除此之外,它们基本上是相同的(测试传入的谓词以查看某个项目是否是您想要的)