2010-10-29 84 views
0

我有一個具有泛型類型的私有變量的類。
在類中我已經聲明瞭一個Foo方法。
檢查IL後,我發現方法Push的目標實際上是方法調用set_Property2,而不是類的字段。
編譯器如何在兩者之間建立連接?有關字段參考的MSIL問題

 

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 
} 
 
+0

您的字段在L_0024加載,然後將方法的參數放在堆棧上,然後在L_0052處調用Push。問題是什麼? – kvb 2010-10-29 17:12:28

+0

這裏有太多的事情要做,以便於分析。請提供一個簡短但完整的程序來證明這一點,儘可能使用簡短的方法。 – 2010-11-05 15:54:27

+0

我注意到它僅在使用對象初始值設定項時發生。當我創建A的新實例並將其推入堆棧時,ldfld行將從L_0002中省略並插入L_001a,這對我來說很有意義。 – Sagi 2010-11-05 16:37:39

回答

2

我沒有看到一個問題。下面是選項:

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

翻譯爲:

  • 創建對象,並在當地的0
  • 負載_STACK場
  • 加載本地0
  • 呼叫推
存儲參考

現在你的「嵌入式」對象初始值vers離子:

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

翻譯爲:

  • 負載_STACK場
  • 創建本地0
  • 負載對象和存儲本地0
  • 呼叫推

在這兩個情況下,堆棧結束了字段和參數。只是在「嵌入式​​」對象初始化版本中,加載字段和調用方法之間還有更多的事情要做。

0

根據反射器

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,assign,field reference)。
L_001d:varaible參考 (可變參考,set_Property2,set_Property1 ...)

L_001e:推送方法需要一個目標和一個參數。如果我假設這條線與L_000f線相同,那麼位於堆棧頂部的目標是set_Property2。

我不明白你爲什麼寫了堆棧結束字段和參數。

+0

這不是一個真正的答案。作爲一個問題編輯會更好。 – 2010-11-11 22:19:36