안녕하세요? 맨날맑음입니다.

닷넷의 리플렉션(Reflection)을 이용하면 어셈블리의 메터데이터 정보를 알아올 수 있고, 이를 이용해 지연바인딩(Lazy Binding)이나 동적으로 코드를 생성할 수 있습니다. 이번 포스팅에서는 리플렉션을 이용한 동적 코드생성에 대해 알아 보도록 하겠습니다.

 

간단한 예제를 통해 동적 코드생성에 대해 알아 볼 텐데요. 예제는 어셈블리를 동적으로 생성/실행하는 콘솔어플리케이션 프로젝트(App)와, 동적으로 코드를 생성하는 클래스 라이브러리 프로젝트(CodeGenerator)로 구성 됩니다.

CodeGenerator 클래스에서는 동적으로 DynamicAssembly를 생성하고, DynamicClass, DynamicMethod를 만들어 그 안에 "Dynamic Method Call"이라는 메시지를 프린트하는 코드를 작성하게 만들도록 하겠습니다.

 

  1. 파일 -> 새로 만들기 -> 프로젝트를 선택하여 빈 솔루션을 생성합니다.
  2. 솔루션 탐색기의 솔루션 탭을 마우스 오른쪽 클릭하여, 콘솔어플리케이션 프로젝트(App)와 클래스라이브러리 프로젝트(CodeGenerator)를 생성합니다.
  3. Programe.cs 와 Class1.cs의 이름을 각각 App와 CodeGenerator로 변경합니다.

#1. CodeGenerator 클래스 작성

CodeGenerator.cs에 다음의 코드를 입력합니다.

public class CodeGenerator
{
    public Type DynamicType { getprivate set; }
    public CodeGenerator()
    {
        //현재 어플리케이션 도매인을 가져온다.
        AppDomain currentDomain = AppDomain.CurrentDomain;
        //생성하려는 어셈블리의 이름을 설정한다.
        AssemblyName assemName = new AssemblyName("DynamicAssembly");         //어셈블리를 생성         AssemblyBuilder assemBuilder = currentDomain.DefineDynamicAssembly(assemName, AssemblyBuilderAccess.Run);
        //모듈 생성         ModuleBuilder moduleBuilder = assemBuilder.DefineDynamicModule("DynamicModule");         //클래스 생성         TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicClass"TypeAttributes.Public);         //메서드 생성         MethodBuilder methodBuilder = typeBuilder.DefineMethod("DynamicMethod"MethodAttributes.Public, nullnull);         //동적 코드 생성         ILGenerator msil = methodBuilder.GetILGenerator();         msil.EmitWriteLine("Dynamic Method Call");         msil.Emit(OpCodes.Ret);         //타입 정보 저장     DynamicType = typeBuilder.CreateType();     }
}

 

DynamicType이라는 필드가 있고, 이 필드는 동적으로 생성 할 Class의 Type을 저장하는 용도로 쓰입니다. 생성자에서는 동적으로 코드를 생성하기 위한 단계를 진행하는데요. 어셈블리->모듈->클래스->메서드->코드 생성의 단계로 진행을 하게 됩니다. 마지막에 보이는 ILGenerator 클래스를 이용하여 msil코드를 생성 할 수 있게 됩니다. 예제에서는 간단히 EmitWriteLine 메서드를 이용하여 "Dynamic Method Call"이라는 문자열을 화면에 뿌리는 코드를 생성 하였습니다.

 

#2. App 클래스 작성

App프로젝트로에서 CodeGenerator 프로젝트를 참조 추가 합니다.


				

App.cs 에 다음의 코드를 추가합니다.

class App
{
    static void Main(string[] args)
    {
        //CodeGenerator클래스 생성
        CodeGenerator.CodeGenerator codeGenerator = new CodeGenerator.CodeGenerator();
        //동적으로 추가 한 Type을 얻어옴
        Type DynamicType = codeGenerator.DynamicType;
        //Activator 클래스를 이용하여 인스턴스 생성
        object obj = Activator.CreateInstance(DynamicType);
        //동적으로 생성한 메소드를 얻어옴
        MethodInfo methodInfo = DynamicType.GetMethod("DynamicMethod");
        //실행
        methodInfo.Invoke(obj, null);
    } }

Main메서드의 로직은 간단합니다. 우선 CodeGenerator 클래스의 public 필드인 DynamicType에서 동적으로 생성한 Class의 Type을 얻어옵니다. Activator 클래스를 이용하여 클래스의 인스턴스를 생성하고, MethodInfo 클래스로 미리 생성한 DynamicMethod를 얻어와 실행합니다.

 

실행결과는 Dynamic Method Call이 나오면 의도한 결과이겠죠?

 


				

이상 동적으로 코드를 생성하고, Reflection을 이용하여 동적으로  인스턴스를 생성 / 실행하는 방법이었습니다. 

감사합니다.

 

소스코드 빌드 환경 : Windows7 x64, Visual Studio2010, .NET Framwork4.0

Posted by 맨날맑음
,