Enumerating via interface - performance loss

后端 未结 4 904
情书的邮戳
情书的邮戳 2021-02-13 11:57

I had a little dispute (which was very close to holy war:) ) with my colleage, about the performance of access to list via indeces VS via enumerator. To operat

4条回答
  •  忘了有多久
    2021-02-13 12:41

    You can see the code here:

    static void Main()
    {
    
        List list = new List(Enumerable.Range(1,10000));
    
        int total = 0;
        foreach (var i in list)
        {
            total += i;
        }
        IEnumerable enumerable = list;
        foreach (var i in enumerable)
        {
            total += i;
        }
        Console.ReadLine();
    }
    

    Which generates this IL. Notice the difference between

    System.Collections.Generic.List`1/Enumerator
    

    and

    System.Collections.Generic.IEnumerable`1 
    

    and note that it is a ValueType (struct):

    .method private hidebysig static void  Main() cil managed
    {
      .entrypoint
      // Code size       146 (0x92)
      .maxstack  2
      .locals init ([0] class [mscorlib]System.Collections.Generic.List`1 list,
               [1] int32 total,
               [2] int32 i,
               [3] class [mscorlib]System.Collections.Generic.IEnumerable`1 enumerable,
               [4] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator CS$5$0000,
               [5] bool CS$4$0001,
               [6] class [mscorlib]System.Collections.Generic.IEnumerator`1 CS$5$0002)
      IL_0000:  nop
      IL_0001:  ldc.i4.1
      IL_0002:  ldc.i4     0x2710
      IL_0007:  call       class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Range(int32,
                                                                                                                                      int32)
      IL_000c:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1)
      IL_0011:  stloc.0
      IL_0012:  ldc.i4.0
      IL_0013:  stloc.1
      IL_0014:  nop
      IL_0015:  ldloc.0
      IL_0016:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator()
      IL_001b:  stloc.s    CS$5$0000
      .try
      {
        IL_001d:  br.s       IL_002d
        IL_001f:  ldloca.s   CS$5$0000
        IL_0021:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current()
        IL_0026:  stloc.2
        IL_0027:  nop
        IL_0028:  ldloc.1
        IL_0029:  ldloc.2
        IL_002a:  add
        IL_002b:  stloc.1
        IL_002c:  nop
        IL_002d:  ldloca.s   CS$5$0000
        IL_002f:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext()
        IL_0034:  stloc.s    CS$4$0001
        IL_0036:  ldloc.s    CS$4$0001
        IL_0038:  brtrue.s   IL_001f
        IL_003a:  leave.s    IL_004b
      }  // end .try
      finally
      {
        IL_003c:  ldloca.s   CS$5$0000
        IL_003e:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator
        IL_0044:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
        IL_0049:  nop
        IL_004a:  endfinally
      }  // end handler
      IL_004b:  nop
      IL_004c:  ldloc.0
      IL_004d:  stloc.3
      IL_004e:  nop
      IL_004f:  ldloc.3
      IL_0050:  callvirt   instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator()
      IL_0055:  stloc.s    CS$5$0002
      .try
      {
        IL_0057:  br.s       IL_0067
        IL_0059:  ldloc.s    CS$5$0002
        IL_005b:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current()
        IL_0060:  stloc.2
        IL_0061:  nop
        IL_0062:  ldloc.1
        IL_0063:  ldloc.2
        IL_0064:  add
        IL_0065:  stloc.1
        IL_0066:  nop
        IL_0067:  ldloc.s    CS$5$0002
        IL_0069:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
        IL_006e:  stloc.s    CS$4$0001
        IL_0070:  ldloc.s    CS$4$0001
        IL_0072:  brtrue.s   IL_0059
        IL_0074:  leave.s    IL_008a
      }  // end .try
      finally
      {
        IL_0076:  ldloc.s    CS$5$0002
        IL_0078:  ldnull
        IL_0079:  ceq
        IL_007b:  stloc.s    CS$4$0001
        IL_007d:  ldloc.s    CS$4$0001
        IL_007f:  brtrue.s   IL_0089
        IL_0081:  ldloc.s    CS$5$0002
        IL_0083:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
        IL_0088:  nop
        IL_0089:  endfinally
      }  // end handler
      IL_008a:  nop
      IL_008b:  call       string [mscorlib]System.Console::ReadLine()
      IL_0090:  pop
      IL_0091:  ret
    } // end of method Program2::Main
    

提交回复
热议问题