所以我知道Find()
只是List<T>
方法,而First()
是任何IEnumerable<T>
的扩展名。我也知道如果没有传递参数,First()
将返回第一个元素,而Find()
将抛出异常。最后,我知道如果找不到元素,First()
将抛出异常,而Find()
将返回类型的默认值。
我希望能够解决我实际要问的问题。这是一个计算机科学问题,并在计算层面处理这些方法。我已经明白IEnumerable<T>
扩展并不总是像人们期望的那样运行。所以这是Q,我的意思是从“接近金属”的角度来看: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()
等内容。
答案 0 :(得分:52)
以下是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
使用for
循环,因为它已经知道元素的数量,First
使用foreach循环,因为它不知道它。
答案 1 :(得分:17)
First
会在找不到任何内容时抛出异常,FirstOrDefault
但与Find
完全相同(除了它如何遍历元素)。
答案 2 :(得分:5)
BTW查找等于FirstOrDefault()
而不是First()
。因为如果First()
的谓词不满足任何列表元素,您将获得异常。
这里返回一个dotpeek,另一个很好的自由反射器替代了一些ReSharper功能
此处适用于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&lt;&gt; .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);
}
答案 3 :(得分:2)
由于List<>
未以任何方式编入索引,因此必须遍历所有值才能找到特定值。因此,与通过可枚举遍历列表(除了创建可枚举的辅助对象实例)相比,它没有太大区别。
那就是说,请记住,Find
函数的创建时间早于First
扩展方法(Framework V2.0 vs. V3.5),我怀疑它们是否会实现Find
如果List<>
类与扩展方法同时实现。
答案 4 :(得分:2)
1-如果实体不在上下文中,但Find()
将引发异常,则Null
返回First()
2- Find()
返回已添加到上下文但尚未保存到数据库的实体
答案 5 :(得分:0)
在枚举器而不是List上使用Find会是否也会产生潜在的性能成本,因为枚举器可能不必获取整个列表来满足谓词?相反,如果你已经有了一个列表,那么Find会更好。