它確實不管是做什麼,它必須做的最快捷的方式。
當上一個IEnumerable
使用,這將是沿着線:
foreach(var item in source)
if(predicate(item))
return true;
return false;
或爲不帶謂詞的變體:
using(var en = source.GetEnumerator())
return en.MoveNext();
當數據庫它會針對其運行有點像
SELECT EXISTS(SELECT null FROM [some table] WHERE [some where clause])
依此類推。如何執行將依次取決於可用於實現WHERE子句的索引,因此它可以是快速索引查找,找到第一個匹配時中止的全表掃描,或索引查找,然後是部分表掃描,然後中止首先找到匹配,取決於那個。
其他的Linq提供者還有其他的實現,但通常負責人會試圖至少合理地有效。
總而言之,您可以依賴它至少比調用FirstOrDefault
更有效率,因爲FirstOrDefault
使用類似的方法,但必須返回完整的對象(可能構造它)。同樣,!All(inversePredicate)
往往與this answer的Any(predicate)
相當。
Single
是一個例外
更新:從這點以下上不再適用於.NET的核心,它改變的Single
實施。
重要的是要注意,在linq-to對象的情況下,帶有謂詞的Single
和SingleOrDefault
的超負荷不會停止在發現的故障上。儘管對Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
明顯的辦法是這樣的:
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
/* do null checks */
using(var en = source.GetEnumerator())
while(en.MoveNext())
{
var val = en.Current;
if(predicate(val))
{
while(en.MoveNext())
if(predicate(en.Current))
throw new InvalidOperationException("too many matching items");
return val;
}
}
throw new InvalidOperationException("no matching items");
}
實際的實現是一樣的東西:現在
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
/* do null checks */
var result = default(TSource);
long tally = 0;
for(var item in source)
if(predicate(item))
{
result = item;
checked{++tally;}
}
switch(tally)
{
case 0:
throw new InvalidOperationException("no matching items");
case 1:
return result;
default:
throw new InvalidOperationException("too many matching items");
}
}
,而成功的Single
將需要掃描的一切,這可能意味着一個不成功的Single
比需要的要慢得多(甚至可能會拋出未記錄的錯誤),並且如果意外重複的原因是將項目複製到序列中的錯誤 - 並因此使其遠大於它應該的大小,則應該有所幫助的Single
你發現這個問題現在正在拖延。
SingleOrDefault
具有相同的問題。
這隻適用於linq-to-objects,但它做.Where(predicate).Single()
而不是Single(predicate)
更安全。
[Enumerable.Any()']的文檔(https://msdn.microsoft.com/en-us/library/vstudio/bb337697%28v=vs.100%29.aspx)明確指出了答案對此:*只要確定結果,源的枚舉就會停止。* –