1

Reflection Emit (IL コード) を使用してカスタム プロキシを作成しようとしています。すべてが正常に機能していますが、2 番目のメソッドを呼び出すと、常に結果が得られず、null 値 (NullReferenceException) をボックス化解除しようとして execption が発生します。

これは、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.

どんな助けもありません。前もって感謝します。

4

1 に答える 1

2

PEVerify の出力は、問題の内容を正確に示しています。8B のボックス命令はスタック上にあると予想さObjectれていましたが、その時点でInt32はそこにありました。しかし、私たちはInt32そこにいたいと思っています。それが私たちがボックスにしたいものです. では、なぜbox期待するのObjectでしょうか。あなたがそう言ったからです。パラメータ toboxボックス化するタイプではなく、ボックス化するタイプを示します。

したがって、コードを次のように変更します。

IL_008b:  box        [mscorlib]System.Int32

問題を解決する必要があります。

8B から 95 までのすべての手順は、何もしない (ボックス、ストア、ロード、アンボックス) ための複雑な方法のように見えますが。それらをそこに置く特別な理由がない場合は、それらを削除する必要があります。

于 2012-07-24T14:42:30.243 に答える