Does foreach evaluate the array at every iteration?

前端 未结 5 982
失恋的感觉
失恋的感觉 2020-11-27 20:34

I want to create a foreach which skips the first item. I\'ve seen elsewhere that the easiest way to do this is to use myCollection.Skip(1), but I h

5条回答
  •  北海茫月
    2020-11-27 21:10

    Pull it out and it probably becomes clearer.

    var myCollection = new List();
    var skipped = myCollection.Skip(1);
    
    foreach (var i in skipped) {
        Console.WriteLine(i.ToString());
    }
    
    
    

    So skipped is just an IEnumerable that foreach is enumerates now.

    Here's what the IL looks like in that case:

    IL_0000:  newobj      System.Collections.Generic.List..ctor
    IL_0005:  stloc.0     // myCollection
    IL_0006:  ldloc.0     // myCollection
    IL_0007:  ldc.i4.1    
    IL_0008:  call        System.Linq.Enumerable.Skip
    IL_000D:  stloc.1     // skipped
    IL_000E:  ldloc.1     // skipped
    IL_000F:  callvirt    System.Collections.Generic.IEnumerable.GetEnumerator
    IL_0014:  stloc.3     // CS$5$0000
    IL_0015:  br.s        IL_0029
    IL_0017:  ldloc.3     // CS$5$0000
    IL_0018:  callvirt    System.Collections.Generic.IEnumerator.get_Current
    IL_001D:  stloc.2     // i
    IL_001E:  ldloc.2     // i
    IL_001F:  callvirt    System.Object.ToString
    IL_0024:  call        System.Console.WriteLine
    IL_0029:  ldloc.3     // CS$5$0000
    IL_002A:  callvirt    System.Collections.IEnumerator.MoveNext
    IL_002F:  brtrue.s    IL_0017
    IL_0031:  leave.s     IL_003D
    IL_0033:  ldloc.3     // CS$5$0000
    IL_0034:  brfalse.s   IL_003C
    IL_0036:  ldloc.3     // CS$5$0000
    IL_0037:  callvirt    System.IDisposable.Dispose
    IL_003C:  endfinally  
    

    The IL for your code looks similar:

    var myCollection = new List();
    
    foreach (var i in myCollection.Skip(1)) {
        Console.WriteLine(i.ToString());
    }
    
    IL_0000:  newobj      System.Collections.Generic.List..ctor
    IL_0005:  stloc.0     // myCollection
    IL_0006:  ldloc.0     // myCollection
    IL_0007:  ldc.i4.1    
    IL_0008:  call        System.Linq.Enumerable.Skip <-- 1 Call to .Skip() outside the loop.
    IL_000D:  callvirt    System.Collections.Generic.IEnumerable.GetEnumerator
    IL_0012:  stloc.2     // CS$5$0000
    IL_0013:  br.s        IL_0027
    IL_0015:  ldloc.2     // CS$5$0000
    IL_0016:  callvirt    System.Collections.Generic.IEnumerator.get_Current
    IL_001B:  stloc.1     // i
    IL_001C:  ldloc.1     // i
    IL_001D:  callvirt    System.Object.ToString
    IL_0022:  call        System.Console.WriteLine
    IL_0027:  ldloc.2     // CS$5$0000
    IL_0028:  callvirt    System.Collections.IEnumerator.MoveNext
    IL_002D:  brtrue.s    IL_0015
    IL_002F:  leave.s     IL_003B
    IL_0031:  ldloc.2     // CS$5$0000
    IL_0032:  brfalse.s   IL_003A
    IL_0034:  ldloc.2     // CS$5$0000
    IL_0035:  callvirt    System.IDisposable.Dispose
    IL_003A:  endfinally  
    
    
    

    It still has just the one .Skip() call.

    提交回复
    热议问题