2013-02-16 51 views
0

我只是好奇我将如何使用Emit调用字段上的方法。调用字段的方法

我有这个类生成

public class AClass : IDynamicProxyTestInterface 
{ 
    private DynamicProxy<IDynamicProxyTestInterface> proxy; 
    public AClass(DynamicProxy<IDynamicProxyTestInterface> p) 
    { 
     proxy = p; 
    } 

    public void Hello() 
    { 
     // Here I want to do the following 
     Int32 code = 123456; 
     proxy.HandleCall(code); 
    } 
} 

注释的部分是我一直在努力搞清楚。

我有这样的代码(注释掉的东西是东西,我已经打开和关闭,试图使其工作)

var methodBuilder = typeBuilder.DefineMethod(
    methodInfo.Name, 
    MethodAttributes.Public | MethodAttributes.Virtual, 
    methodInfo.ReturnType, 
    methodInfo.GetParameters().Select(p => p.GetType()).ToArray() 
    ); 
var methodIlGen = methodBuilder.GetILGenerator(); 

// Add proxy call to method 
var emptyAction = new DynamicProxyOnBuilder(); 
ProxyCalls.Add(methodInfo.GetHashCode(), emptyAction); 

// Drop method info hash into local variable 0 
//var hash = methodInfo.GetHashCode(); 
//methodIlGen.Emit(OpCodes.Ldc_I4, hash); 
//methodIlGen.DeclareLocal(typeof(Int32), false); 
//methodIlGen.Emit(OpCodes.Stloc_0); 

// Create local variable for instance of this DynamicProxy 
methodIlGen.Emit(OpCodes.Ldarg_0); 
methodIlGen.Emit(OpCodes.Ldflda, proxyField); 
var var2 = methodIlGen.DeclareLocal(this.GetType()); 
methodIlGen.Emit(OpCodes.Stloc,var2); 
////methodIlGen.EmitWriteLine(proxyField); 
////methodIlGen.Emit(OpCodes.St); 
//methodIlGen.Emit(OpCodes.Ldloc,var2); 
methodIlGen.Emit(OpCodes.Call, this.GetType().GetMethods().First(x => x.Name == "HandleCall")); 

任何想法,我做错了什么?

BTW,我得到的错误是 Common Language Runtime detected an invalid program.JIT Compiler encountered an internal limitation.

+0

什么是所有注释掉的代码?也似乎是很多不相关的代码。 – leppie 2013-02-16 07:30:05

+2

为什么不直接在发布模式下编译C#代码段,并查看IL生成的内容。这应该是微不足道的。 – leppie 2013-02-16 07:31:47

+0

'(注释掉的东西是我一直在打开和关闭的东西,试图使其工作)' – 2013-02-16 07:32:00

回答

3

通常在这种情况下做的最好的事情是写在C#代码,编译它,然后检查编译IL。

在你的情况下,虽然你缺少的主要是你的方法必须完成一个“ret”指令,并且HandleCall应该是虚拟的。所以你只需要(假设HandleCall具有void返回类型)

Ldflda [proxyField] // push the this pointer 
Ldc_I4 123   // push the argument 
Callvirt [HandleCode] // call the method 
Ret     // return 
+0

顺便说一句,如果该方法不是虚拟的,则不需要使用'callvirt'而不是'call'。但这通常是一个好主意,因为'call'不会执行'null'检查。 – svick 2013-02-16 14:17:19

+0

ret在那里,它超出了范围,对不起。 – 2013-02-16 17:55:35

+0

@svick - 你当然是对的;我没有仔细阅读样本!我认为这是一个接口调用,而不是非虚拟方法。 – 2013-02-18 10:56:47