編集:少し近づいて見ました。拡張メソッドWhereEnumerableIterator
によって返される は、実際にはメソッドをオーバーライドし、述語を 1 つのコールバックに結合します。Where
Where
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) {
return new Enumerable.WhereEnumerableIterator<TSource>(
this.source,
Enumerable.CombinePredicates<TSource>(this.predicate, predicate));
}
private static Func<TSource, bool> CombinePredicates<TSource>(
Func<TSource, bool> predicate1, Func<TSource, bool> predicate2
) {
return (TSource x) => predicate1(x) && predicate2(x);
}
したがって、私のマシンで見た速度の違いは、おそらく別の原因によるものです。
elements
最初の例では、コレクションを 1 回
ループして条件を満たすアイテムitem > 3
を検索し、もう一度条件を満たしたアイテムを検索しますitem % 2 == 0
。
2 番目の例では、コレクションを 1 回ループしてelements
、条件を満たす項目を見つけますitem > 3 && item % 2 == 0
。
提供されている例では、2 番目のループはelements
1 回だけループするため、常に最初よりも高速です。
これは、私のマシン (.NET 3.5) で取得したかなり一貫した結果の例です。
var stopwatch = new System.Diagnostics.Stopwatch();
var elements = Enumerable.Range(1, 100000000);
var results = default(List<int>);
stopwatch.Start();
results = elements.Where(n => n > 3).Where(n => n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
stopwatch.Reset();
stopwatch.Start();
results = elements.Where(n => n > 3 && n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
Console.WriteLine("Done");
Console.ReadLine();
結果:
00:00:03.0932811
00:00:02.3854886
Done
編集:
@Rawling は、私の説明が POCO オブジェクトのコレクションで使用される LINQ にのみ適用されるという点で正しいです。LINQ-to-SQL、NHibernate、EF などへのインターフェイスとして使用すると、結果はより実装に依存します。