2016-12-09 8 views
2

メソッドをクラスからILコードに変換し、それを呼び出してメソッドを実行します。私が従う例はmsdn:https://msdn.microsoft.com/en-us/library/system.reflection.emit.methodbuilder.createmethodbody(v=vs.110).aspxです。クラスメソッドをILに変換し、実行時に実行します。

これは私が必要とするものを正確に示しています。私の問題は、クラスメソッドからILコードを生成することです。私はバイト配列を埋めるために、次の呼び出しを試みた

public class MethodBodyDemo 
{ 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 
} 

だから基本的に私は、例えば、クラスで定義されたメソッドから、次の

byte[] ILcodes = new byte[] { 
     0x02, /* 02h is the opcode for ldarg.0 */ 
    0x03, /* 03h is the opcode for ldarg.1 */ 
    0x58, /* 58h is the opcode for add  */ 
    0x2A /* 2Ah is the opcode for ret  */ 
}; 

を入力する必要があります

var ILcodes = typeof(MethodBodyDemo).GetMethod("Add").GetMethodBody().GetILAsByteArray(); 

私が作成している例ですが、例外があります: "Common Language Runtimeが無効なプログラムを検出しました。

public class MethodBodyDemo 
{ 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 

    // This class will demonstrate how to create a method body using 
    // the MethodBuilder.CreateMethodBody(byte[], int) method. 

    public static Type BuildDynType() 
    { 

     Type addType = null; 

     AppDomain currentDom = Thread.GetDomain(); 

     AssemblyName myAsmName = new AssemblyName(); 
     myAsmName.Name = "MyDynamicAssembly"; 

     AssemblyBuilder myAsmBldr = currentDom.DefineDynamicAssembly(
          myAsmName, 
          AssemblyBuilderAccess.RunAndSave); 

     // The dynamic assembly space has been created. Next, create a module 
     // within it. The type Point will be reflected into this module. 

     ModuleBuilder myModuleBldr = myAsmBldr.DefineDynamicModule("MyModule"); 

     TypeBuilder myTypeBldr = myModuleBldr.DefineType("Adder"); 

     MethodBuilder myMthdBldr = myTypeBldr.DefineMethod("Add", 
           MethodAttributes.Public | 
           MethodAttributes.Static, 
           typeof(int), 
           new Type[] 
           {typeof(int), typeof(int)}); 
     // Build the array of Bytes holding the MSIL instructions. 

    // byte[] ILcodes = new byte[] { 
    //   0x02, /* 02h is the opcode for ldarg.0 */ 
     // 0x03, /* 03h is the opcode for ldarg.1 */ 
     // 0x58, /* 58h is the opcode for add  */ 
     // 0x2A /* 2Ah is the opcode for ret  */ 
     //}; 

     var ILcodes = typeof(MethodBodyDemo).GetMethod("Add").GetMethodBody().GetILAsByteArray(); 

     myMthdBldr.CreateMethodBody(ILcodes, ILcodes.Length); 

     addType = myTypeBldr.CreateType(); 

     return addType; 
    } 

    public static void TestExecMethod() 
    { 

     Type myType = BuildDynType(); 
     Console.WriteLine("---"); 
     Console.Write("Enter the first integer to add: "); 
     int aVal = Convert.ToInt32(Console.ReadLine()); 

     Console.Write("Enter the second integer to add: "); 
     int bVal = Convert.ToInt32(Console.ReadLine()); 

     object adderInst = Activator.CreateInstance(myType, new object[0]); 

     Console.WriteLine("The value of adding {0} to {1} is: {2}.", 
        aVal, bVal, 
         myType.InvokeMember("Add", 
           BindingFlags.InvokeMethod, 
           null, 
           adderInst, 
           new object[] { aVal, bVal })); 
    } 

} 

呼び出すことによって実行します。

MethodBodyDemo.TestExecMethod(); 

任意のヘルプしてください?

+0

ちょうど好奇心から、あなたは最終的に何をしようとしていますか?:)直接(または間接的にリフレクションを使用して)メソッドを呼び出すか、 'System.Reflection.Emit.ILGenerator'を使用して命令を作成することに間違っていますか? – Caramiriel

+0

私はちょっと混乱しています。基本的に、新しいメソッドをオブジェクトに動的に追加して呼び出しようとしていますか? – EJoshuaS

+0

私が探しているのは、メソッドを別のシステムに送信し、そのシステムがそれを実行するメソッドですが、他のシステムは使用されているライブラリについて認識していません。上記のコードはそうです、唯一のことはILcodeを埋める方法ですか? –

答えて

2

Releaseモードでプロジェクトをビルドし、次のいずれかを実行します

static

public int Add(int x, int y) 
{ 
    return x + y; 
} 

そして、このように

MethodBuilder myMthdBldr = myTypeBldr.DefineMethod("Add", 
          MethodAttributes.Public | 
          MethodAttributes.Static, 
          typeof(int), 
          new Type[] 
          {typeof(int), typeof(int)}); 

または変更ここでは、この方法をMethodAttributes.Static属性を削除しますあなたのために働くはずです。

enter image description here

しかし、私はあなたがそれを他のシステムにバイトを渡すと、それを実行したいコメントで見た、私の答えはちょうどあなたが疑問を持っている一例です。現実には、Simon Svenssonがコメントに書いた理由から、これはうまくいかないでしょう。 (他のメソッド\タイプ\フィールドへの参照なしに、すべてのメソッドが静的であり、戻り値が3 + 4のような純粋な操作でない限り)。

これは動作させるためにはまだ理論的に。

3

私は同様のことをするライブラリの著者です。既存のメソッドのオペコードを読み取り、番号付きトークンの代わりにMethodInfoを含む汎用オペコードアイテムに再解釈し、これらのメソッドコピーを作成します。これはクロスアセンブリで動作し、あなたの場合でも動作します。

モンキーパッチゲームに設計されましたが、「クリアテキスト」の汎用オペコードを別のシステムに転送して、宛先がタイプルックアップを実行してローカルアセンブリの正しいオペコードを取得できるように変更できました。

プロジェクトはMITライセンスであり、Harmonyと呼ばれています。

関連する問題