通过动态方法获取静态字段的值

时间:2012-07-12 09:38:45

标签: c# windows-phone-7 reflection static dynamicmethod

我有以下课程:

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;
    }

但我需要类似的东西(OpCodes来自类似方法的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;
    }

这个想法很简单,动态方法适用于非静态字段(ldfld操作码和对象),但是当我尝试访问静态字段时,我收到异常:

System.InvalidProgramException was unhandled
  Message=InvalidProgramException

1 个答案:

答案 0 :(得分:2)

基于反编译代码编写的IL代码也是一个好主意,但您仍然需要了解自己在做什么。

如果您查看the documentation for Br_S,您会发现自己应该使用Label,而不是int。我认为代码中的Br_S分支到字节偏移量为9的指令,但我不知道哪条指令是什么,你永远不应该写这样的代码。

如果您只想加载静态字段的值并返回它,则不需要任何局部变量或分支。以下就足够了:

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

这样做是它将值加载到评估堆栈上然后立即返回。它可以工作,因为从返回值的方法返回时,评估堆栈上的单个值将用作返回值。