MSIL关于字段引用的问题

时间:2010-10-29 16:03:49

标签: compiler-construction cil

我有一个类,它有一个类型为泛型Stack的私有变量 在课堂上我宣布了一个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
        });
    }
}

和IL:


.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 个答案:

答案 0 :(得分:2)

我没有看到问题。以下是选项:

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

转换为:

  • 在本地0
  • 中创建对象和商店引用
  • 加载_stack字段
  • 加载本地0
  • 致电推送

现在你的“嵌入式”对象初始化版本:

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

转换为:

  • 加载_stack字段
  • 创建对象并存储在本地0
  • 加载本地0
  • 致电推送

在这两种情况下,堆栈都以字段和参数结束。只是在“嵌入式​​”对象初始化程序版本中,加载字段和调用方法之间会有更多的东西。

答案 1 :(得分:0)

根据反射器

L_0001:“this”引用位于顶部 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,assign,field reference)。
L_001d:可变参考 (变量引用,set_Property2,set_Property1 ......)

L_001e:push方法需要一个目标和一个参数。如果我假设此行与行L_000f的作用相同,则堆栈顶部的目标为set_Property2。

我不明白为什么你写这个堆栈最终会得到字段和参数。