我正在尝试使用Reflection Emit(IL代码)制作自定义代理。 一切都工作正常,但是当我调用第二种方法时,我总是得不到结果,并且我得到一个尝试取消装箱空值的执行(NullReferenceException)。
这是使用Emit动态生成的IL代码。 (我评论了重要的部分)
.method public hidebysig newslot virtual final
instance int32 TestCall(int32 A_1,
int32 A_2) cil managed
{
// Code size 155 (0x9b)
.maxstack 5
.locals init (class [mscorlib]System.Reflection.MethodInfo V_0,
class [BaseProxy.Console]BaseProxy.Console.TestClass V_1,
object[] V_2,
bool V_3,
object V_4)
IL_0000: ldc.i4 0x2
IL_0005: newarr [mscorlib]System.Object
IL_000a: stloc.2
IL_000b: ldloc.2
IL_000c: ldc.i4 0x0
IL_0011: ldarg A_1
IL_0015: nop
IL_0016: nop
IL_0017: box [mscorlib]System.Int32
IL_001c: stelem.ref
IL_001d: ldloc.2
IL_001e: ldc.i4 0x1
IL_0023: ldarg A_2
IL_0027: nop
IL_0028: nop
IL_0029: box [mscorlib]System.Int32
IL_002e: stelem.ref
IL_002f: ldtoken [BaseProxy.Console]BaseProxy.Console.TestClass
IL_0034: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0039: ldstr "TestCall"
IL_003e: call instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string)
IL_0043: stloc.0
IL_0044: ldarg.0
IL_0045: ldfld class [BaseProxy.Console]BaseProxy.Console.TestClass TestClassProxy::wrappedObject
IL_004a: stloc.1
IL_004b: ldc.i4.1
IL_004c: stloc.3
IL_004d: ldarg.0
IL_004e: ldfld class [BaseProxy.Console]BaseProxy.Console.BasicInterceptor TestClassProxy::interception
IL_0053: ldloc.0
IL_0054: ldloc.2
IL_0055: ldloc.1
IL_0056: ldloca.s V_3
IL_0058: callvirt instance object [BaseProxy.Console]BaseProxy.Console.BasicInterceptor::Before(class [mscorlib]System.Reflection.MethodInfo,
object[],
object,
bool&)
**//Here everything is ok, i can get the result.**
IL_005d: box [mscorlib]System.Object
IL_0062: stloc.s V_4
IL_0064: nop
IL_0065: ldloc.3
IL_0066: brfalse.s IL_0093
IL_0068: ldarg.0
IL_0069: ldfld class [BaseProxy.Console]BaseProxy.Console.TestClass TestClassProxy::wrappedObject
IL_006e: ldloc.2
IL_006f: ldc.i4 0x0
IL_0074: ldelem.ref
IL_0075: unbox.any [mscorlib]System.Int32
IL_007a: ldloc.2
IL_007b: ldc.i4 0x1
IL_0080: ldelem.ref
IL_0081: unbox.any [mscorlib]System.Int32
IL_0086: callvirt instance int32 [BaseProxy.Console]BaseProxy.Console.TestClass::TestCall(int32,
int32)
**\\This Call Always return nothing (null)**
IL_008b: box [mscorlib]System.Object
IL_0090: stloc.s V_4
IL_0092: nop
IL_0093: ldloc.s V_4
**\\And i get a Exception here because loc 4 is null**
IL_0095: unbox.any [mscorlib]System.Int32
IL_009a: ret
} // end of method TestClassProxy::TestCall
TestCall方法是一个返回int32值的非常简单的方法。 我已经在TestCall中设置了一个断点并且它很好。
PEVerify给我回复了以下错误:
[IL]: Error: [GeneratedProxyModule.dll : TestClassProxy::TestCall][offset 0x0000008B][found Int32][expected ref 'System.Object'] Unexpected type on the stack.
任何有用的帮助。 提前谢谢。
答案 0 :(得分:2)
PEVerify输出可以准确地告诉您问题所在。 8B处的盒子指令预期在堆栈上Object
,但当时Int32
就在那里。但是我们希望Int32
在那里,这就是我们想要的东西。那么为什么box
期望Object
?因为你这么说。 The parameter to box
tells it from what type to box, not to what type to box.
所以,将代码更改为:
IL_008b: box [mscorlib]System.Int32
应该解决你的问题。
尽管8B和95之间的所有指令看起来都像是一种复杂的方式(盒子,存储,加载,取消装箱)给我。如果你没有任何特殊的理由让它们在那里,你应该删除它们。