2012-07-12 47 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