MSIL вопрос о поле ссылки - PullRequest
       20

MSIL вопрос о поле ссылки

0 голосов
/ 29 октября 2010

У меня есть класс с закрытой переменной типа универсального стека.
Внутри класса я объявил метод Foo.
После изучения IL я заметил, что целью метода Push на самом деле является вызов метода set_Property2, а не поле класса.
Как компилятор на самом деле устанавливает связь между ними?


public class A
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
}

public class ShortDemo
{
    private Stack<A> _stack = new Stack<A>();

    private void Foo()
    {
        _stack.Push(new A()
        {
            Property1 = 1,
            Property2 = 2
        });
    }
}

И ИЛ:


.method private hidebysig instance void Foo() cil managed
{
    .maxstack 3
    .locals init (
        [0] class ConsoleApplication1.A g__initLocal0)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldfld class [System]System.Collections.Generic.Stack1 ConsoleApplication1.ShortDemo::_stack
    L_0007: newobj instance void ConsoleApplication1.A::.ctor()
    L_000c: stloc.0 
    L_000d: ldloc.0 
    L_000e: ldc.i4.1 
    L_000f: callvirt instance void ConsoleApplication1.A::set_Property1(int32)
    L_0014: nop 
    L_0015: ldloc.0 
    L_0016: ldc.i4.2 
    L_0017: callvirt instance void ConsoleApplication1.A::set_Property2(int32)
    L_001c: nop 
    L_001d: ldloc.0 
    L_001e: callvirt instance void [System]System.Collections.Generic.Stack1::Push(!0)
    L_0023: nop 
    L_0024: ret 
}

Ответы [ 2 ]

2 голосов
/ 05 ноября 2010

Я не вижу проблемы. Вот варианты:

A a = new A() { ... };
_stack.Push(args)

переводится как:

  • Создать объект и сохранить ссылку в локальном 0
  • Загрузить поле _stack
  • Загрузка локальная 0
  • Call Push

Теперь ваша версия встроенного инициализатора объекта:

_stack.Push(new A() { ... });

переводится как:

  • Загрузить поле _stack
  • Создать объект и хранить в локальном 0
  • Загрузка локальная 0
  • Call Push

В обоих случаях стек заканчивается полем и аргументом. Просто во «встроенной» версии инициализатора объекта происходит больше вещей между загрузкой поля и вызовом метода.

0 голосов
/ 10 ноября 2010

Согласно отражателю

L_0001: ссылка «это» вверху.
L_0002: ссылка на поле находится сверху после извлечения значения из стека.
L_0007: новый объект ConsoleApplication1.A находится наверху.
L_000c: выражение присваивания находится вверху после извлечения значения из стека.

(Итак, теперь у нас есть два выражения, назначаемых сверху, и ссылка на поле).

L_000d: доступная ссылка наверху.
L_000e: буквальное значение int вверху.
L_000f: вызов метода set_Property1 вверху после извлечения литерального значения для использования в качестве
аргумента и ссылки на переменную в качестве цели.
(теперь у нас есть вызов метода 3 выражений для set_Property1, назначение выражения, а затем ссылка на поле
).

L_0017: то же самое, что L_000f, заканчивающийся добавлением вызова метода в стек (set_Property2, set_Property1, назначить, ссылка на поле).
L_001d: доступная ссылка (ссылка на переменную, set_Property2, set_Property1 ...)

L_001e: метод push ожидает цель и один аргумент. Если я предполагаю, что эта строка работает так же, как и строка L_000f, то целью на вершине стека является set_Property2.

Я не понимаю, почему вы написали, что стек заканчивается полем и аргументом.

...