foreach
на самом деле не всегда использует IEnumerable[<T>]
/ IEnumerator[<T>]
API вообще. Во-первых, это на самом деле не требуется: все, что требуется, — это метод GetEnumerator()
, который возвращает что-то с bool MoveNext()
и Current {get;}
— например, List<T>
имеет собственный итератор. Этот подход также был распространен в .NET 1.1, чтобы избежать упаковки, отдавая предпочтение пользовательскому итератору.
Однако в случае с массивами все, пожалуй, даже интереснее; учитывать:
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
.
person
Marc Gravell
schedule
27.06.2012
ArrayList
,HashTable
и т. д.) было бы сложно их вернуть... - person AakashM   schedule 27.06.2012