Задать вопрос
  • C#: почему foreach над массивом структур быстрее, чем for?

    @izjalvovich Автор вопроса
    IL:
    Foreach
    spoiler

    .locals init (
          [0] valuetype Garbage.QS[] V_0,
          [1] int32 V_1,
          [2] valuetype Garbage.QS q
        )
    
        // [47 23 - 47 26]
        IL_0000: ldarg.0      // this
        IL_0001: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
        IL_0006: stloc.0      // V_0
        IL_0007: ldc.i4.0
        IL_0008: stloc.1      // V_1
    
        IL_0009: br.s         IL_0022
        // start of loop, entry point: IL_0022
    
          // [47 14 - 47 19]
          IL_000b: ldloc.0      // V_0
          IL_000c: ldloc.1      // V_1
          IL_000d: ldelem       Garbage.QS
          IL_0012: stloc.2      // q
    
          // [48 7 - 48 22]
          IL_0013: ldarg.0      // this
          IL_0014: ldloc.2      // q
          IL_0015: call         instance bool Garbage.Tests::ByValue(valuetype Garbage.QS)
          IL_001a: brfalse.s    IL_001e
    
          // [49 9 - 49 21]
          IL_001c: ldc.i4.1
          IL_001d: ret
    
          IL_001e: ldloc.1      // V_1
          IL_001f: ldc.i4.1
          IL_0020: add
          IL_0021: stloc.1      // V_1
    
          // [47 20 - 47 22]
          IL_0022: ldloc.1      // V_1
          IL_0023: ldloc.0      // V_0
          IL_0024: ldlen
          IL_0025: conv.i4
          IL_0026: blt.s        IL_000b
        // end of loop
    
        // [50 5 - 50 18]
        IL_0028: ldc.i4.0
        IL_0029: ret



    ForeachIn:
    spoiler

    .locals init (
          [0] valuetype Garbage.QS[] V_0,
          [1] int32 V_1,
          [2] valuetype Garbage.QS qs
        )
    
        // [58 24 - 58 27]
        IL_0000: ldarg.0      // this
        IL_0001: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
        IL_0006: stloc.0      // V_0
        IL_0007: ldc.i4.0
        IL_0008: stloc.1      // V_1
    
        IL_0009: br.s         IL_0023
        // start of loop, entry point: IL_0023
    
          // [58 14 - 58 20]
          IL_000b: ldloc.0      // V_0
          IL_000c: ldloc.1      // V_1
          IL_000d: ldelem       Garbage.QS
          IL_0012: stloc.2      // qs
    
          // [59 7 - 59 24]
          IL_0013: ldarg.0      // this
          IL_0014: ldloca.s     qs
          IL_0016: call         instance bool Garbage.Tests::ByRef(valuetype Garbage.QS&)
          IL_001b: brfalse.s    IL_001f
    
          // [60 9 - 60 21]
          IL_001d: ldc.i4.1
          IL_001e: ret
    
          IL_001f: ldloc.1      // V_1
          IL_0020: ldc.i4.1
          IL_0021: add
          IL_0022: stloc.1      // V_1
    
          // [58 21 - 58 23]
          IL_0023: ldloc.1      // V_1
          IL_0024: ldloc.0      // V_0
          IL_0025: ldlen
          IL_0026: conv.i4
          IL_0027: blt.s        IL_000b
        // end of loop
    
        // [61 5 - 61 18]
        IL_0029: ldc.i4.0
        IL_002a: ret



    For:
    spoiler

    .locals init (
          [0] int32 i
        )
    
        // [69 10 - 69 19]
        IL_0000: ldc.i4.0
        IL_0001: stloc.0      // i
    
        IL_0002: br.s         IL_001e
        // start of loop, entry point: IL_001e
    
          // [70 7 - 70 27]
          IL_0004: ldarg.0      // this
          IL_0005: ldarg.0      // this
          IL_0006: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
          IL_000b: ldloc.0      // i
          IL_000c: ldelem       Garbage.QS
          IL_0011: call         instance bool Garbage.Tests::ByValue(valuetype Garbage.QS)
          IL_0016: brfalse.s    IL_001a
    
          // [71 9 - 71 21]
          IL_0018: ldc.i4.1
          IL_0019: ret
    
          // [69 37 - 69 40]
          IL_001a: ldloc.0      // i
          IL_001b: ldc.i4.1
          IL_001c: add
          IL_001d: stloc.0      // i
    
          // [69 21 - 69 35]
          IL_001e: ldloc.0      // i
          IL_001f: ldarg.0      // this
          IL_0020: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
          IL_0025: ldlen
          IL_0026: conv.i4
          IL_0027: blt.s        IL_0004
        // end of loop
    
        // [72 5 - 72 18]
        IL_0029: ldc.i4.0
        IL_002a: ret



    ForRef:
    spoiler

    .locals init (
          [0] int32 i
        )
    
        // [80 10 - 80 19]
        IL_0000: ldc.i4.0
        IL_0001: stloc.0      // i
    
        IL_0002: br.s         IL_001e
        // start of loop, entry point: IL_001e
    
          // [81 7 - 81 29]
          IL_0004: ldarg.0      // this
          IL_0005: ldarg.0      // this
          IL_0006: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
          IL_000b: ldloc.0      // i
          IL_000c: ldelema      Garbage.QS
          IL_0011: call         instance bool Garbage.Tests::ByRef(valuetype Garbage.QS&)
          IL_0016: brfalse.s    IL_001a
    
          // [82 9 - 82 21]
          IL_0018: ldc.i4.1
          IL_0019: ret
    
          // [80 37 - 80 40]
          IL_001a: ldloc.0      // i
          IL_001b: ldc.i4.1
          IL_001c: add
          IL_001d: stloc.0      // i
    
          // [80 21 - 80 35]
          IL_001e: ldloc.0      // i
          IL_001f: ldarg.0      // this
          IL_0020: ldfld        valuetype Garbage.QS[] Garbage.Tests::_qs
          IL_0025: ldlen
          IL_0026: conv.i4
          IL_0027: blt.s        IL_0004
        // end of loop
    
        // [84 5 - 84 18]
        IL_0029: ldc.i4.0
        IL_002a: ret

    Написано
  • C#: почему foreach над массивом структур быстрее, чем for?

    @izjalvovich Автор вопроса
    rPman, для структур ссылочные члены копируются через копирование ссылки, а не объекта
    К тому же, при вызове ByValue в for результат не отличается от ByRef
    Написано
  • C#: почему foreach над массивом структур быстрее, чем for?

    @izjalvovich Автор вопроса
    for - ровно такой же сахар над while, к тому же итератор занимается ровно тем же, обращаясь к массиву по индексу https://github.com/dotnet/runtime/blob/main/src/li...
    Написано