2016-12-09 10 views
2

메서드를 클래스에서 IL 코드로 변환 한 다음 호출하여 실행하고 싶습니다. 내가 따르는 예는 msdn : https://msdn.microsoft.com/en-us/library/system.reflection.emit.methodbuilder.createmethodbody(v=vs.110).aspx입니다.클래스 메서드를 IL로 변환하여 런타임에 실행하십시오.

정확히 내가 원하는 것을 보여줍니다, 내 문제는 클래스 메서드에서 ILcodes 생성하는 것입니다.

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

다음은 내가 만드는 예제이지만 예외를 제공합니다. "공용 언어 런타임에서 잘못된 프로그램을 발견했습니다."

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 모드에서 프로젝트를 빌드하고 다음 중 하나를 수행합니다

을 여기에 MethodAttributes.Static 속성

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

를 제거하거나 static

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

가이 방법을 변경 그리고이 당신을 위해 일해야합니다.

enter image description here

그러나, 나는 당신이 다른 시스템에 바이트를 전달하고 그것을 실행하려는 의견에서 본, 내 대답은 당신이 질문에있는 예입니다. 실제로 이것은 Simon Svensson이 논평에서 쓴 이유 때문에 효과가 없을 것입니다. (모든 메소드가 정적이고 다른 메소드 \ 타입 \ 필드에 대한 참조없이 순 조작 (예 : 3 + 4 리턴)을하지 않는 한).

여전히 이론적으로는 어떤 마법을 사용하여 작동시킬 수는 있지만 실제로는 불가능합니다. .

3

나는 비슷한 것을하는 도서관의 저자이다. 기존 메소드의 opcode를 읽고, 번호가 매겨진 토큰 대신 MethodInfo를 포함하는 일반 opcode 항목으로 다시 해석하고 메소드 사본을 작성합니다. 이것은 교차 조립 작업을하며 귀하의 경우에도 효과가 있습니다.

이 패치는 원숭이 패치 게임에 맞게 설계되었지만 "일반 텍스트"로 일반 opcode를 다른 시스템으로 전송하여 대상에서 유형 조회를 수행하여 로컬 어셈블리에 올바른 opcode를 얻을 수 있도록 수정할 수 있습니다.

프로젝트는 MIT 라이선스이며 Harmony입니다.