を理解するには、いつandを使用するかyield
を理解する必要があります(どちらかを使用する必要があるため)。次の例は、違いを理解するのに役立ちます。IEnumerator
IEnumerable
IEnumerator<int>
まず、次のクラスを見てください。これは 2つのメソッドを実装していますIEnumerable<int>
。2 つのメソッドのコードは似ていますが、使用方法に大きな違いがあることをお見せします。
// 2 iterators, one as IEnumerator, one as IEnumerable
public class Iterator
{
public static IEnumerator<int> IterateOne(Func<int, bool> condition)
{
for(var i=1; condition(i); i++) { yield return i; }
}
public static IEnumerable<int> IterateAll(Func<int, bool> condition)
{
for(var i=1; condition(i); i++) { yield return i; }
}
}
を使用しているIterateOne
場合は、次の操作を実行できます。
// 1. Using IEnumerator allows to get item by item
var i=Iterator.IterateOne(x => true); // iterate endless
// 1.a) get item by item
i.MoveNext(); Console.WriteLine(i.Current);
i.MoveNext(); Console.WriteLine(i.Current);
// 1.b) loop until 100
int j; while (i.MoveNext() && (j=i.Current)<=100) { Console.WriteLine(j); }
1.a) プリント:
1
2
1.b) プリント:
3
4
...
100
1.a) ステートメントが実行された直後にカウントを継続するためです。
を使ってアイテムごとに進められることがわかりますMoveNext()
。
対照的に、より快適にするためにLINQステートメントもIterateAll
使用できます。foreach
// 2. Using IEnumerable makes looping and LINQ easier
var k=Iterator.IterateAll(x => x<100); // limit iterator to 100
// 2.a) Use a foreach loop
foreach(var x in k){ Console.WriteLine(x); } // loop
// 2.b) LINQ: take 101..200 of endless iteration
var lst=Iterator.IterateAll(x=>true).Skip(100).Take(100).ToList(); // LINQ: take items
foreach(var x in lst){ Console.WriteLine(x); } // output list
2.a) プリント:
1
2
...
99
2.b) プリント:
101
102
...
200
注:IEnumerator<T>
とはジェネリックであるためIEnumerable<T>
、どの型でも使用できます。ただし、簡単にするためにint
、例では type を使用しましたT
。
つまり、戻り値の型の 1 つIEnumerator<ProductMixHeader>
またはIEnumerable<ProductMixHeader>
(質問で言及したカスタム クラス) を使用できます。
型List<ProductMixHeader>
はこれらのインターフェイスを実装していません。これが、そのように使用できない理由です。ただし、例 2.b)は、そこからリストを作成する方法を示しています。
追加してリストを作成している場合.ToList()
、メモリ内のすべての要素のリストを作成することをIEnumerable
意味しますが、要素の遅延作成を許可します-パフォーマンスの観点から、要素がジャストインタイムで列挙されることを意味します-できるだけ遅く、ただし を使用するとすぐに.ToList()
、すべての要素がメモリ内に作成されます。LINQ は、舞台裏でこの方法でパフォーマンスを最適化しようとします。
すべての例の DotNetFiddle