初心者の質問です。
C# の配列は、非ジェネリック (クラシック) IEnumerator を返します。他のコレクションはいずれかを提供できます。
一般に、たとえば型安全性の理由から、ジェネリック列挙子が利用可能な場合はそれを使用する方がよいでしょうか? 非汎用オプションが望ましい場合はありますか?
初心者の質問です。
C# の配列は、非ジェネリック (クラシック) IEnumerator を返します。他のコレクションはいずれかを提供できます。
一般に、たとえば型安全性の理由から、ジェネリック列挙子が利用可能な場合はそれを使用する方がよいでしょうか? 非汎用オプションが望ましい場合はありますか?
通常、質問で述べたように、型の安全性のために、ジェネリック列挙を使用することを強くお勧めします。
オブジェクトのコレクションだけを格納する場合は、非ジェネリック列挙を選択できます。したがって、 を記述する代わりに、反復内で実際のオブジェクト型IEnumerable<object>
を記述IEnumerable
して把握します (必要な場合は、通常は必要です)。
foreach
IEnumerable[<T>]
/ IEnumerator[<T>]
APIを実際に常に使用しているわけではありません。まず、実際には必須ではありません。必要なのは、 andを使用して何かをGetEnumerator()
返すメソッドだけです。たとえば、カスタム イテレータがあります。このアプローチは、.NET 1.1 でも一般的で、カスタム イテレータを優先することでボックス化を回避しました。bool MoveNext()
Current {get;}
List<T>
ただし、配列の場合は、さらに興味深いことがあります。検討:
static void Main()
{
foreach(var i in GetData()) Console.WriteLine(i);
}
static int[] GetData()
{
int[] data = { 1, 2, 3, 4, 5 };
return data;
}
ここで、Main
にコンパイルされます(//
コメントは私のものです):
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 i,
[1] int32[] CS$6$0000,
[2] int32 CS$7$0001)
// int[] arr = GetData()
L_0000: call int32[] ConsoleApplication7.Program::GetData()
L_0005: stloc.1
// int j = 0
L_0006: ldc.i4.0
L_0007: stloc.2
// run end-condition of for loop first...
L_0008: br.s L_0018
// i = arr[j]
L_000a: ldloc.1
L_000b: ldloc.2
L_000c: ldelem.i4
L_000d: stloc.0
// Console.WriteLine(i);
L_000e: ldloc.0
L_000f: call void [mscorlib]System.Console::WriteLine(int32)
// j++
L_0014: ldloc.2
L_0015: ldc.i4.1
L_0016: add
L_0017: stloc.2
// j < arr.Length
L_0018: ldloc.2
L_0019: ldloc.1
L_001a: ldlen
L_001b: conv.i4
L_001c: blt.s L_000a
L_001e: ret
}
これは、列挙子 APIをまったく使用しません。実際にはfor
ループとして実装されています。