2

我目前正在玩反射,我的短代码有问题:

public class Test
{
    public Test()
    { 

    }
    public string Call()
    {
        string called = "Called";
        return called;
    }
}

和用法:

var method = new DynamicMethod("dummy", null, Type.EmptyTypes);
var g = method.GetILGenerator();

g.DeclareLocal(typeof(Object));
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes));
g.Emit(OpCodes.Stloc, 0);
g.Emit(OpCodes.Nop);
g.Emit(OpCodes.Ldloc, 0);
g.Emit(OpCodes.Call, typeof(Test).GetMethod("Call", new Type[]{}));
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{ typeof(string) }));
g.Emit(OpCodes.Nop);
//g.Emit(OpCodes.Pop); - used in debugging
g.Emit(OpCodes.Ret);

var action = (Action)method.CreateDelegate(typeof(Action));
action();

Console.Read();

所以。我正在尝试在运行时创建新方法。在该方法中,我正在创建新的空测试实例。然后,我尝试将其设置为位置 (0),即 if Object 类型。然后我正在加载它并调用它的方法 Call 来获取字符串。最后,我试图将字符串结果放在屏幕上。我的代码适用于“Ldloc_0”。当调用“调用”方法时会发生错误。有谁知道如何解决这个问题?请帮忙。

4

2 回答 2

4

Call(...)并且是实例方法;尝试使用CallVirt而不是OpCodes.Call. Console.WriteLine静态 方法,所以应该使用Call.

如果有疑问,只需为您想要发出的内容编写 C#,然后在反射器中查看它。

请注意,Ldloc / 0随后的 call/callvirt 将无法验证 - 也应该有一个演员表:

g.DeclareLocal(typeof(Object));
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes));
g.Emit(OpCodes.Stloc, 0);
g.Emit(OpCodes.Ldloc, 0);
g.Emit(OpCodes.Castclass, typeof(Test));
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { }));
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
       new Type[] { typeof(string) }));
g.Emit(OpCodes.Ret);

或更好:

g.DeclareLocal(typeof(Test));
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes));
g.Emit(OpCodes.Stloc_0);
g.Emit(OpCodes.Ldloc_0);
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { }));
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
           new Type[] { typeof(string) }));
g.Emit(OpCodes.Ret);

或最好:

g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes));
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { }));
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
          new Type[] { typeof(string) }));
g.Emit(OpCodes.Ret);
于 2012-06-21T11:45:48.093 回答
1

将局部变量声明为“Test”类型而不是“Object”类型:

g.DeclareLocal(typeof(Test));
于 2012-06-21T11:53:14.147 回答