我想创建一个foreach跳过第一项的。我在其他地方看到过,最简单的方法是使用myCollection.Skip(1),但是我有一个问题:
foreach
myCollection.Skip(1)
MSDN文档上.Skip()描述它“在序列中绕过指定数量的元素,然后返回其余元素”。这是否意味着
.Skip()
foreach(object i in myCollection.Skip(1)) { ... }
程序.Skip(1)每次foreach迭代都必须执行吗?还是foreach(有点像switch)不需要对数组进行多次求值?
.Skip(1)
switch
创建一个虚拟对象var _dummy = myCollection.Skip(1)并对其进行迭代会更有效吗?
var _dummy = myCollection.Skip(1)
我只是以此来嘲笑你的代码
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.Range IL_000A: ldc.i4.1 IL_000B: call System.Linq.Enumerable.Skip//Call to Skip IL_0010: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator IL_0015: stloc.1 // CS$5$0000 IL_0016: br.s IL_0026 IL_0018: ldloc.1 // CS$5$0000 IL_0019: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current IL_001E: stloc.0 // v IL_001F: ldloc.0 // v IL_0020: call LINQPad.Extensions.Dump IL_0025: pop IL_0026: ldloc.1 // CS$5$0000 IL_0027: callvirt System.Collections.IEnumerator.MoveNext IL_002C: stloc.2 // CS$4$0001 IL_002D: ldloc.2 // CS$4$0001 IL_002E: brtrue.s IL_0018 IL_0030: leave.s IL_0042 IL_0032: ldloc.1 // CS$5$0000 IL_0033: ldnull IL_0034: ceq IL_0036: stloc.2 // CS$4$0001 IL_0037: ldloc.2 // CS$4$0001 IL_0038: brtrue.s IL_0041 IL_003A: ldloc.1 // CS$5$0000 IL_003B: callvirt System.IDisposable.Dispose IL_0040: nop IL_0041: endfinally
如您所见Skip,仅被调用一次。
Skip
等效的C#代码看起来像这样
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();//Get the enumerator try { 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 code here } } finally { if (e != null) ((IDisposable)e).Dispose(); }
考虑下面的代码,如果foreach VeryLongRunningMethodThatReturnsEnumerable在每次迭代中调用,那将是一场噩梦。语言设计中的巨大缺陷。幸运的是它没有那样做。
VeryLongRunningMethodThatReturnsEnumerable
foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable()) { //Do something with that obj }