我只是以此来嘲笑你的代码
foreach(var v in Enumerable.Range(1,10).Skip(1)) v.Dump();
这是生成的IL。
IL_0001: nop IL_0002: ldc.i4.1 IL_0003: ldc.i4.s 0A IL_0005: call System.Linq.Enumerable.RangeIL_000A: ldc.i4.1 IL_000B: call System.Linq.Enumerable.Skip//Call to SkipIL_0010: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumeratorIL_0015: stloc.1 // CS$5$0000IL_0016: br.s IL_0026IL_0018: ldloc.1 // CS$5$0000IL_0019: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_CurrentIL_001E: stloc.0 // vIL_001F: ldloc.0 // vIL_0020: call LINQPad.Extensions.DumpIL_0025: pop IL_0026: ldloc.1 // CS$5$0000IL_0027: callvirt System.Collections.IEnumerator.MoveNextIL_002C: stloc.2 // CS$4$0001IL_002D: ldloc.2 // CS$4$0001IL_002E: brtrue.s IL_0018IL_0030: leave.s IL_0042IL_0032: ldloc.1 // CS$5$0000IL_0033: ldnull IL_0034: ceq IL_0036: stloc.2 // CS$4$0001IL_0037: ldloc.2 // CS$4$0001IL_0038: brtrue.s IL_0041IL_003A: ldloc.1 // CS$5$0000IL_003B: callvirt System.IDisposable.DisposeIL_0040: nop IL_0041: endfinally
如您所见
Skip,仅被调用一次。
等效的C#代码看起来像这样
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();//Get the enumeratortry{ int m;//This variable is here prior to c#5.0 while(e.MoveNext()) {//int m; is declared here starting from c#5.0 m = (int)(int)e.Current; //Your pre here }}finally{ if (e != null) ((IDisposable)e).Dispose();}考虑下面的代码,如果foreach
VeryLongRunningMethodThatReturnsEnumerable在每次迭代中调用,那将是一场噩梦。语言设计中的巨大缺陷。幸运的是它没有那样做。
foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable()){ //Do something with that obj}


