内部的には、最初のバージョンは次のようにコンパイルされます。
public IEnumerable<T> GoodItems
{
get
{
foreach (var item in _list)
if (item.IsGood)
yield return item;
}
}
一方、2 つ目は次のようになります。
public IEnumerable<T> GoodItems
{
get
{
foreach (var item in GoodItemsHelper)
yield return item;
}
}
private IEnumerable<T> GoodItemsHelper
{
get
{
foreach (var item in _list)
if (item.IsGood)
yield return item;
}
}
LINQのWhere
句は、遅延実行で実装されます。foreach (...) yield return ...
したがって、パターンを適用する必要はありません。自分自身のために、そして潜在的にランタイムのために、より多くの作業を行っています。
2 番目のバージョンが 1 番目と同じものになるかどうかはわかりません。意味的には、この 2 つは、前者が 1 ラウンドの遅延実行を行い、後者が 2 ラウンドを行うという点で異なります。これらの理由から、2番目はより複雑になると私は主張します。
質問する必要がある本当の質問は、IEnumerable を公開するときに、どのような保証を行っているかということです。単純に前方反復を提供したいと言っているのですか? それとも、インターフェースが遅延実行を提供していると述べていますか?
以下のコードでは、ランダム アクセスなしで単純に前方列挙を提供することを目的としています。
private List<Int32> _Foo = new List<Int32>() { 1, 2, 3, 4, 5 };
public IEnumerable<Int32> Foo
{
get
{
return _Foo;
}
}
しかし、ここでは不要な計算を避けたいと思います。結果が要求された場合にのみ、高価な計算を実行したいと考えています。
private List<Int32> _Foo = new List<Int32>() { 1, 2, 3, 4, 5 };
public IEnumerable<Int32> Foo
{
get
{
foreach (var item in _Foo)
{
var result = DoSomethingExpensive(item);
yield return result;
}
}
}
両方のバージョンのFoo
外観は同じに見えますが、内部実装は異なることを行います。気をつけていただきたい部分です。LINQ を使用する場合、ほとんどのオペレーターが実行を延期するため、実行の延期について心配する必要はありません。独自のコードでは、必要に応じて 1 番目または 2 番目を使用することをお勧めします。