Compiler construction 关于字段引用的MSIL问题

Compiler construction 关于字段引用的MSIL问题,compiler-construction,cil,Compiler Construction,Cil,我有一个类,它有一个类型为generic Stack的私有变量。 在类中,我声明了一个Foo方法。 在检查了IL之后,我注意到方法推送的目标实际上是方法调用集\u Property2,而不是类的字段。 编译器实际上是如何在两者之间建立连接的 public class A { public int Property1 { get; set; } public int Property2 { get; set; } } public class ShortDemo { p

我有一个类,它有一个类型为generic Stack的私有变量。
在类中,我声明了一个Foo方法。
在检查了IL之后,我注意到方法推送的目标实际上是方法调用集\u 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
        });
    }
}

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

A a = new A() { ... };
_stack.Push(args)
翻译为:

  • 在本地0中创建对象和存储引用
  • 加载堆栈字段
  • 加载本地0
  • 呼叫推送
现在,您的“嵌入式”对象初始值设定项版本:

_stack.Push(new A() { ... });
翻译为:

  • 加载堆栈字段
  • 在本地0中创建对象并存储
  • 加载本地0
  • 呼叫推送

在这两种情况下,堆栈都以字段和参数结束。只是在“嵌入式”对象初始值设定项版本中,在加载字段和调用方法之间有更多的工作要做。

根据reflector

L_0001:“此”参考位于顶部。
L_0002:从堆栈中弹出值后,字段引用位于顶部。
L_0007:新控制台应用程序1。对象位于顶部。
L_000c:从堆栈中弹出值后,赋值表达式位于顶部。

(现在我们有两个表达式分配在顶部和字段引用)。

L_000d:顶部的可变参考。
L_000e:顶部的文字整数值。
L_000f:在弹出文本值以用作参数并将变量引用用作目标后,在顶部设置_Property1方法调用。
(现在我们有3个表达式方法调用来设置_Property1,分配表达式,然后是字段
引用)。

L_0017:与L_000f相同,以添加到堆栈的方法调用结尾 (设置属性2,设置属性1,分配,字段引用)。
L_001d:可变参考 (变量引用,集合属性2,集合属性1…)

L_001e:push方法需要一个目标和一个参数。如果我假设这一行与L_000f行的工作方式相同,则位于堆栈顶部的目标设置为_Property2


我不明白你为什么写堆栈以字段和参数结束。

你的字段在L_0024加载,然后方法的参数被放置在堆栈上,然后在L_0052调用
Push
。问题是什么?这里的事情太多了,很难分析。请提供一个简短但完整的程序来演示这一点,并尽可能使用简短的方法。我注意到,只有在使用对象初始值设定项时才会出现这种情况。当我创建A的新实例并将其推送到堆栈时,ldfld行从L_0002中省略并插入到L_001a,这对我来说是有意义的。这不是一个真正的答案。作为一个问题编辑会更好。
_stack.Push(new A() { ... });