2013-05-07 3 views
3

교육용으로 간단한 .net 컴파일러를 만들려고합니다. 파싱, 스캐닝 및 AST 구축 후 나는 Reflection.Emit.ILGenerator을 사용하여 .net 어셈블리를 생성합니다. 여기 Reflection.Emit.ILGenerator :: Emit, 제 3 자 .net 라이브러리에서 메서드 호출

어셈블리 생성을위한 내 샘플 코드입니다 :

using System; 

public class Program 
{ 
    public Program() 
    { 
    } 

    public static void Main() 
    { 
     Console.WriteLine("Test!"); 
    } 
} 

다음으로는 하나의 간단한 타사 라이브러리를 만드는거야 :

static void Main(string[] args) 
{ 
    string moduleName = "Test.exe"; 

    AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(moduleName)); 
    AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save); 
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName); 
    TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Public); 
    MethodBuilder mainMethod = typeBuilder.DefineMethod(
     "Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), System.Type.EmptyTypes); 


    ILGenerator il = mainMethod.GetILGenerator(); 

    il.Emit(OpCodes.Ldstr, "Test!"); 
    il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new System.Type[] { typeof(string) })); 
    il.Emit(OpCodes.Ret); 

    typeBuilder.CreateType(); 
    moduleBuilder.CreateGlobalFunctions(); 
    assemblyBuilder.SetEntryPoint(mainMethod); 
    assemblyBuilder.Save(moduleName); 
} 

모든 것이 잘 작동이 코드는 다음과 같은 클래스와 실행 파일 생성 ThirdPartyLibrary.dll에 빌드하는 클래스 :

using System; 

namespace ThirdPartyLibrary 
{ 
    public class MyPrint 
    { 
     public static void Print(string s) 
     { 
      Console.WriteLine("Third party prints: " + s); 
     } 
    } 
} 

이제 알았습니다. 내 라이브러리에서 MyPrint.Print 메서드 호출에 Console.WriteLine 메서드 호출을 교체하고 같은 결과 코드 뭔가 얻을 : 지금까지 내가 내 ThirdPartyLibrary.dll 파일을 읽을 수 있어야 이해

using System; 
using ThirdPartyLibrary; 

public class Program 
{ 
    public Program() 
    { 
    } 

    public static void Main() 
    { 
     MyPrint.Print("Test!"); 
    } 
} 

를, 그것은 다음의 모든 유형을 얻기 위해 어떻게 든 반영 MyPrint 유형을 사용할 수 있습니다. 마지막으로 csc.exe 사용과 같은 myCompiler.exe 인수로 참조를 연결할 수 있기를 바랍니다.

그래서 질문은 다음과 같습니다

  • 어떻게 할 수 있나요?
  • 어떻게이 이름이 지정 되었습니까? (나는 무엇을 Google에 이해할 수 없다)
  • 나는이 대신에 Reflection 대신 다른 프레임 워크를 사용해야 할까?
  • 다른 제안 ...

답변

4

여기에 단 하나의 변화는 대상 방법 :

var targetMethod = Assembly.LoadFrom("ThirdPartyLibrary.dll") 
    .GetType("ThirdPartyLibrary.MyPrint") 
    .GetMethod("Print", new [] {typeof(string)}); 
... 
il.Emit(OpCodes.Ldstr, "Test!"); 
il.Emit(OpCodes.Call, targetMethod); 
il.Emit(OpCodes.Ret); 

그래서 대신 Console.WriteLine 사용하여, 우리는 MyPrint.Print를 호출합니다.

  • 어떻게 수행하나요? A : 위와 같이
  • 어떻게 이름이 붙어 있습니까? A : IL 세대, 메타 프로그래밍, 리플렉션
  • 리플렉션 대신 다른 프레임 워크를 사용해야 할 수도 있습니다. A : 반영은 대부분의 시나리오를 다루고 있습니다. 내가 십자 프레임 워크 타겟팅을 할 수 있기 때문에 몇 군데에서 IKVM.Reflection.dll을 사용합니다.하지만 그럴 필요는 없습니다. 당신이 일 수도 있습니다.은 편리하게 찾을 수 있습니다. 실행시가 아니라 생성시 오류가있는 보고서를 제공하여 IL 생성 (불균형 스택 등)의 고통을 많이 앗아가는 Sigil입니다. Mono.Cecil도 재미 있습니다
+0

정말 멋지 네요! 나는 dll로부터 타입을 얻는 것이 그렇게 간단하지 않을 것이라고 기대하지 않았다. 감사! – FCR