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();

そう。実行時に新しいメソッドを作成しようとしています。そのメソッドでは、新しい空の Test インスタンスを作成しています。次に、オブジェクトの場合のタイプであるロケーション (0) に設定しようとしています。次に、それをロードし、メソッド Call を呼び出して文字列を取得します。最後に、文字列の結果を画面に表示しようとしています。私のコードは「Ldloc_0」で動作します。「Call」メソッドが呼び出されているときにエラーが発生します。この問題を解決する方法を知っている人はいますか?助けてください。

4

2 に答える 2

4

Call(...)インスタンスメソッドです。CallVirtの代わりに使ってみてくださいOpCodes.CallConsole.WriteLine静的 メソッドなので、 を使用する必要がありますCall

疑問がある場合は、出力したいものを C# で記述し、リフレクターで確認してください。

Ldloc / 0call/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

「Object」ではなく「Test」タイプとしてローカル変数を宣言します。

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