Генерация свойства, которое вызывает метод за кулисами - PullRequest
0 голосов
/ 09 января 2020

В настоящее время я работаю над добавлением новой функции в существующий API.

Я определяю новый атрибут, чтобы всякий раз, когда тип отмечен этим указанным атрибутом c, я хотел бы l oop через некоторый список.

Допустим, у меня есть следующий код:

public class TestClass 
{
    List<int> Numbers = new List<int> { 1, 2, 3, 4, 5 };

    public void Sum()
    {
        int total = 0;

        foreach (int i in Numbers)
        {
            total += i;
        }
    }
}

Декомпилированный C# код для метода Sum() -

public class TestClass
{
    public void Sum()
    {
        int num = 0;
        List<int>.Enumerator enumerator = Numbers.GetEnumerator();
        try
        {
            while (enumerator.MoveNext())
            {
                int current = enumerator.Current;
                num += current;
            }
        }
        finally
        {
            ((IDisposable)enumerator).Dispose();
        }
    }
}

и декомпилированный код IL:

.method public hidebysig 
    instance void Sum () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 59 (0x3b)
    .maxstack 2
    .locals init (
        [0] int32,
        [1] valuetype [System.Private.CoreLib]System.Collections.Generic.List`1/Enumerator<int32>,
        [2] int32
    )

    IL_0000: nop
    IL_0001: ldc.i4.0
    IL_0002: stloc.0
    IL_0003: nop
    IL_0004: ldarg.0
    IL_0005: ldfld class [System.Private.CoreLib]System.Collections.Generic.List`1<int32> TestClass::Numbers
    IL_000a: callvirt instance valuetype [System.Private.CoreLib]System.Collections.Generic.List`1/Enumerator<!0> class [System.Private.CoreLib]System.Collections.Generic.List`1<int32>::GetEnumerator()
    IL_000f: stloc.1
    .try
    {
        // sequence point: hidden
        IL_0010: br.s IL_0020
        // loop start (head: IL_0020)
            IL_0012: ldloca.s 1
            IL_0014: call instance !0 valuetype [System.Private.CoreLib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
            IL_0019: stloc.2
            IL_001a: nop
            IL_001b: ldloc.0
            IL_001c: ldloc.2
            IL_001d: add
            IL_001e: stloc.0
            IL_001f: nop

            IL_0020: ldloca.s 1
            IL_0022: call instance bool valuetype [System.Private.CoreLib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
            IL_0027: brtrue.s IL_0012
        // end loop

        IL_0029: leave.s IL_003a
    } // end .try
    finally
    {
        // sequence point: hidden
        IL_002b: ldloca.s 1
        IL_002d: constrained. valuetype [System.Private.CoreLib]System.Collections.Generic.List`1/Enumerator<int32>
        IL_0033: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose()
        IL_0038: nop
        IL_0039: endfinally
    } // end handler

    IL_003a: ret
} // end of method TestClass::Sum

( Декомпилированный код создается с использованием SharpLab.io.)

Особый интерес представляет инструкция IL_0014, который вызывает get_Current(). Соответствующий декомпилированный код C# просто вызывает свойство Current в перечислителе.

Как вывести эту инструкцию, используя MonoCecil? Это не будет работать, если создать MethodReference с имя get_Current, потому что декомпилированный код C# будет тогда get_Current(), а не Current.

...