2012-07-12 43 views
1

獲取靜態字段的值,我有下面的類:通過動態方法

public class TestClass 
{ 
    public static readonly string HELLO = "Hello, "; 

    public static string SayHello(string name) 
    { 
     return HELLO + name; 
    } 
} 

而且我想通過DynamicMethod的訪問HELLO的靜態字段。 用的GetValue標準反射原理:

public static string GetViaInvoke() 
    { 
     Type tcType = typeof(TestClass); 
     FieldInfo fi = tcType.GetField("HELLO"); 
     string result = fi.GetValue(null) as string; 
     return result; 
    } 

但我需要類似的東西(操作碼來自類似的方法的ILDASM):

public static string GetViaDynamicMethod() 
    { 
     Type tcType = typeof(TestClass); 
     FieldInfo fi = tcType.GetField("HELLO"); 

     DynamicMethod dm = new DynamicMethod("getHello", typeof(string), Type.EmptyTypes);    
     ILGenerator iL = dm.GetILGenerator(); 

     iL.DeclareLocal(typeof(string)); 
     iL.Emit(OpCodes.Nop); 
     iL.Emit(OpCodes.Ldsfld, fi); 
     iL.Emit(OpCodes.Stloc_0); 
     iL.Emit(OpCodes.Br_S, 0x09); 
     iL.Emit(OpCodes.Ldloc_0); 
     iL.Emit(OpCodes.Ret); 

     Func<string> fun = dm.CreateDelegate(typeof(Func<string>)) as Func<string>; 
     string result = fun(); 
     return result; 
    } 

的想法是preety簡單,動態方法做工精細與非-static字段(ldfld操作碼和對象),但是當我嘗試存取權限的靜態字段我收到異常:

System.InvalidProgramException was unhandled 
    Message=InvalidProgramException 

回答

1

基於您在反編譯的代碼上編寫的IL代碼是一個不錯的主意,但您仍然需要了解您在做什麼。

如果你看看the documentation for Br_S,你會發現你應該使用Label而不是int。我認爲代碼中的Br_S分支到字節偏移9處的指令,但我不知道哪個指令是這樣的,而且您不應該這樣寫代碼。

如果您只想加載靜態字段的值並將其返回,則不需要任何本地變量或分支。以下就足夠了:

iL.Emit(OpCodes.Ldsfld, fi); 
iL.Emit(OpCodes.Ret); 

這樣做的是它將值加載到評估堆棧上,然後立即返回。它是有效的,因爲當你從一個返回值的方法返回時,評估棧上的單個值被用作返回值。

+0

感謝它的工作。這是我第一個想到的,但它並沒有在我的情況下,這就是爲什麼我玩ildasm和上面的代碼。 br_s的用途是良好的,則有兩種變體,一個: ** 2B < _int8_ >分行在指定的偏移量,短形式** 和第二與目標指令: ** ILGenerator.Emit(操作碼,_LABEL_ )** 但在這種情況下,根本不能使用它。 – user1520293 2012-07-14 09:28:51