.NET 의 동적 컴 파일 기술 을 상세 하 게 소개 합 니 다.

코드 의 동적 컴 파일 과 실행 은.NET 플랫폼 이 우리 에 게 제공 하 는 강력 한 도구 로 유연 하 게 확장(물론 내부 개발 자 를 상대 로)복잡 하고 예측 할 수 없 는 논리 이 며 추가 코드 를 통 해 기 존의 응용 프로그램 을 확장 합 니 다.이것 은 어느 정도 에 우리 에 게 또 다른 확장 방식 을 제공 해 주 었 다.
동적 코드 실행 은 템 플 릿 생 성,논리 확장 등 일부 장소 에 적용 할 수 있 습 니 다.간단 한 예 를 들 어 사이트 의 응답 속 도 를 위해 HTML 정적 페이지 는 우리 의 가장 좋 은 선택 이지 만 데이터 구동 을 바탕 으로 하 는 사 이 트 는 정적 페이지 로 실현 하기 어렵다.그러면 동적 페이지 를 html 로 만 드 는 작업 은 좋 은 응용 장소 일 수도 있다.또한 일부 템 플 릿 의 사용 에 대해 서도 우 리 는 그것 으로 할 수 있다.또한 이 자체 도 플러그 인 작성 방식 입 니 다.
가장 기본 적 인 동적 컴 파일
.Net 은 우리 가 할 수 있 는 모든 기 초 를 실현 하기 위해 강력 한 지 지 를 제공 합 니 다.주로 응용 되 는 두 개의 네 임 스페이스 는 System.Code Dom.Compiler 와 Microsoft.Sharp 또는 Microsoft.VisualBasic 입 니 다.또한 반사 로 당신 의 코드 를 동적 으로 실행 해 야 합 니 다.코드 를 동적 으로 컴 파일 하고 실행 하 는 원 리 는 제 공 된 소스 코드 를 CSharp CodeProvider 에 맡 겨 컴 파일 을 수행 하 는 것 입 니 다.(사실 CSC 와 다 를 바 없 음)컴 파일 오류 가 없 으 면,생 성 된 IL 코드 는 DLL 로 컴 파일 되 어 메모리 에 저장 되 고 특정한 프로그램 도 메 인(기본 값 은 현재)에 불 러 오 며 반사 적 으로 특정한 방법 을 호출 하거나 특정한 이 벤트 를 촉발 합 니 다.플러그 인 이 만 든 방식 이 라 고 말 하 는 이 유 는 바로 이 때 문 입 니 다.우 리 는 미리 정 의 된 핑 계 를 통 해 프로그램 을 조직 하고 확장 하 며 메 인 프로그램 에 전달 하여 실행 할 수 있 습 니 다.코드 를 동적 으로 컴 파일 하고 실행 하 는 기본 적 인 절 차 는 다음 과 같 습 니 다.
・         컴 파일 되 고 실 행 될 코드 를 읽 고 문자열 로 저장 합 니 다.
・         CSharpCodeProvider 대상 인 스 턴 스 설명
・         CSharp CodeProvider 인 스 턴 스 를 호출 하 는 CompileAssembly FromSource 방법 컴 파일
・         생 성 된 대상 의 인 스 턴 스 를 반사 적 으로 생 성 합 니 다(Assembly.Create Instance)
・         그 방법 을 호출 하 다
다음 코드 세 션 은 완전한 컴 파일 과 실행 과정 을 포함 합 니 다.

//get the code to compile

string strSourceCode = this.txtSource.Text;

 

// 1.Create a new CSharpCodePrivoder instance

CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

 

// 2.Sets the runtime compiling parameters by crating a new CompilerParameters instance

CompilerParameters objCompilerParameters = new CompilerParameters();

objCompilerParameters.ReferencedAssemblies.Add("System.dll");

objCompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

objCompilerParameters.GenerateInMemory = true;

 

// 3.CompilerResults: Complile the code snippet by calling a method from the provider

CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromSource(objCompilerParameters, strSourceCode);

 

if (cr.Errors.HasErrors)

{

    string strErrorMsg = cr.Errors.Count.ToString() + " Errors:";

 

    for (int x = 0; x < cr.Errors.Count; x++)

    {

        strErrorMsg = strErrorMsg + "\r
Line: " +

                     cr.Errors[x].Line.ToString() + " - " +

                     cr.Errors[x].ErrorText;

    }

 

    this.txtResult.Text = strErrorMsg;

    MessageBox.Show("There were build erros, please modify your code.", "Compiling Error");

 

    return;

}

 

// 4. Invoke the method by using Reflection

Assembly objAssembly = cr.CompiledAssembly;

object objClass = objAssembly.CreateInstance("Dynamicly.HelloWorld");

if (objClass == null)

{

    this.txtResult.Text = "Error: " + "Couldn't load class.";

    return;

}

 

object[] objCodeParms = new object[1];

objCodeParms[0] = "Allan.";

 

string strResult = (string)objClass.GetType().InvokeMember(

           "GetTime", BindingFlags.InvokeMethod, null, objClass, objCodeParms);

 

this.txtResult.Text = strResult;

설명 이 필요 한 것 은 컴 파일 파 라 메 터 를 전달 할 때 GenerateInMemory 를 true 로 설정 한 것 입 니 다.이 는 생 성 된 DLL 이 메모리 에 불 러 올 것 임 을 나타 냅 니 다.(다음 에 현재 응용 프로그램 도 메 인 에 기본적으로 참조 되 었 습 니 다)GetTime 방법 을 호출 할 때 매개 변 수 를 추가 하여 object 형식의 배열 을 전달 하고 Reflection 의 InvokeMember 를 통 해 호출 해 야 합 니 다.생 성 된 Assembly 의 대상 인 스 턴 스 를 만 들 때 주의해 야 할 네 임 스페이스 는 입력 코드 의 실제 네 임 스페이스 입 니 다.다음은 우리 가 입력 한 테스트 코드 입 니 다.(편 의 를 위해 모든 코드 는 외부 에서 입력 하고 동적 으로 실행 할 때 조정 하지 않 습 니 다)

using System;

namespace Dynamicly

{

    public class HelloWorld

    {

        public string GetTime(string strName)

        {

            return  "Welcome " + strName + ", Check in at " + System.DateTime.Now.ToString();

        }

    }

}

첨부 파일 에서 제공 하 는 프로그램 을 실행 하면 결 과 를 쉽게 얻 을 수 있 습 니 다.
개 선 된 실행 과정
지금 은 모든 것 이 좋아 보 입 니 다.우 리 는 코드 를 컴 파일 하고 코드 를 현재 응용 프로그램 도 메 인 에 불 러 와 서 우리 의 활동 에 참여 할 수 있 습 니 다.그러나 당신 은 가서 이 프로그램 을 마 운 트 해제 하고 싶 습 니까?더 좋 은 컨트롤 프로그램 은?또한 이 프로그램 을 여러 번 실행 할 때 메모리 사용량 이 많 고 실행 할 때마다 메모리 사용량 이 늘 어 나 는 것 을 발견 할 수 있 습 니 다.이 문 제 를 해결 해 야 합 니까?물론 필요 합 니 다.그렇지 않 으 면 이 물건 이 전혀 쓸모 가 없다 는 것 을 알 게 될 것 입 니 다.제 가 실행 해 야 할 큰 응용 프로그램 들 은 제 서버 crzay 를 무 거 운 부담 을 견 디 지 못 하고 미 치 게 할 것 입 니 다.
이 문 제 를 해결 하려 면 응용 프로그램 도 메 인 을 알 아 봐 야 합 니 다.NET Application Domain 은.NET 이 제공 하 는 활동 적 인 프로 세 스(Process)를 실행 하고 탑재 하 는 용기 로,이 프로 세 스 실행 에 필요 한 코드 와 데 이 터 를 애플 리 케 이 션 Domain 이 라 고 하 는 작은 범위 로 격 리 합 니 다.응용 프로그램 이 실 행 될 때 응용 프로그램 도 메 인 은 모든 프로그램 집합/구성 요소 집합 을 현재 응용 프로그램 도 메 인 에 불 러 오고 필요 에 따라 호출 합 니 다.동적 으로 생 성 된 코드/프로그램 집합 에 대해 서 는 관리 할 방법 이 없 는 것 같 습 니 다.그렇지 않 으 면 애플 리 케 이 션 도 메 인 이 제공 하 는 관리 프로그램 집합 방법 으로 Assemblies 를 동적 으로 불 러 오고 제거 하여 성능 을 향상 시 키 는 목적 을 달성 할 수 있 습 니 다.구체 적 으로 어떻게 할 것 인 가 는 앞의 기초 위 에서 다음 과 같은 절 차 를 추가 합 니 다.
・         다른 애플 리 케 이 션 도 메 인 만 들 기
・         동적 생 성(컴 파일)코드 를 디스크 에 저장 합 니 다.
・         공공 원 격 호출 인터페이스 만 들 기
・         원 격 호출 인터페이스의 인 스 턴 스 를 만 듭 니 다.이 인 터 페 이 스 를 통 해 접근 하 는 방법 입 니 다.
다시 말 하면 대상 을 다른 AppDomain 에 불 러 오고 원 격 호출 방법 으로 호출 하 는 것 이다.원 격 호출 이란 응용 프로그램 도 메 인 을 뛰 어 넘 는 호출 이기 때문에 이 대상(동적 코드)은 Marshalby RefObject 류 에 계승 해 야 합 니 다.재 활용 을 위해 이 인 터 페 이 스 는 하나의 공사 에 단독으로 언급 되 었 고 공장 을 제공 하여 매번 의 호출 작업 을 간소화 했다

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Reflection;

 

namespace RemoteAccess

{

    /// <summary>

          /// Interface that can be run over the remote AppDomain boundary.

          /// </summary>

          public interface IRemoteInterface

          {

                   object Invoke(string lcMethod,object[] Parameters);

          }

 

          /// <summary>

          /// Factory class to create objects exposing IRemoteInterface

          /// </summary>

          public class RemoteLoaderFactory : MarshalByRefObject

          {

                   private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

 

                   public RemoteLoaderFactory() {}

 

                   public IRemoteInterface Create( string assemblyFile, string typeName, object[] constructArgs )

                   {

                             return (IRemoteInterface) Activator.CreateInstanceFrom(

                                      assemblyFile, typeName, false, bfi, null, constructArgs,

                                      null, null, null ).Unwrap();

                   }

          }      

}

다음은 원래 의 기초 위 에서 수정 해 야 할 것 은:
・         컴 파일 된 DLL 을 디스크 에 저장 합 니 다.
・         다른 AppDomain 을 만 듭 니 다.
・         IRemote 인터페이스 인터페이스의 인용 을 가 져 옵 니 다.(생 성 된 DLL 을 추가 AppDomain 에 불 러 옵 니 다)
・         InvokeMethod 방법 을 원 격 으로 호출 합 니 다.
・         AppDomain.Unload()방법 으로 프로그램 집합 을 마 운 트 해제 할 수 있 습 니 다.
다음은 이 방안 을 어떻게 활용 하 는 지 보 여 주 는 완전한 코드 입 니 다.

//get the code to compile

string strSourceCode = this.txtSource.Text;

 

//1. Create an addtional AppDomain

AppDomainSetup objSetup = new AppDomainSetup();

objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

AppDomain objAppDomain = AppDomain.CreateDomain("MyAppDomain", null, objSetup);

 

// 1.Create a new CSharpCodePrivoder instance

CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

 

// 2.Sets the runtime compiling parameters by crating a new CompilerParameters instance

CompilerParameters objCompilerParameters = new CompilerParameters();

objCompilerParameters.ReferencedAssemblies.Add("System.dll");

objCompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

 

// Load the remote loader interface

objCompilerParameters.ReferencedAssemblies.Add("RemoteAccess.dll");

 

// Load the resulting assembly into memory

objCompilerParameters.GenerateInMemory = false;

objCompilerParameters.OutputAssembly = "DynamicalCode.dll";

 

// 3.CompilerResults: Complile the code snippet by calling a method from the provider

CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromSource(objCompilerParameters, strSourceCode);

 

if (cr.Errors.HasErrors)

{

    string strErrorMsg = cr.Errors.Count.ToString() + " Errors:";

 

    for (int x = 0; x < cr.Errors.Count; x++)

    {

        strErrorMsg = strErrorMsg + "\r
Line: " +

                     cr.Errors[x].Line.ToString() + " - " +

                     cr.Errors[x].ErrorText;

    }

 

    this.txtResult.Text = strErrorMsg;

    MessageBox.Show("There were build erros, please modify your code.", "Compiling Error");

 

    return;

}

 

// 4. Invoke the method by using Reflection

RemoteLoaderFactory factory = (RemoteLoaderFactory)objAppDomain.CreateInstance("RemoteAccess","RemoteAccess.RemoteLoaderFactory").Unwrap();

 

// with help of factory, create a real 'LiveClass' instance

object objObject = factory.Create("DynamicalCode.dll", "Dynamicly.HelloWorld", null);

 

if (objObject == null)

{

    this.txtResult.Text = "Error: " + "Couldn't load class.";

    return;

}

 

// *** Cast object to remote interface, avoid loading type info

IRemoteInterface objRemote = (IRemoteInterface)objObject;

 

object[] objCodeParms = new object[1];

objCodeParms[0] = "Allan.";

 

string strResult = (string)objRemote.Invoke("GetTime", objCodeParms);

 

this.txtResult.Text = strResult;

 

//Dispose the objects and unload the generated DLLs.

objRemote = null;

AppDomain.Unload(objAppDomain);

 

System.IO.File.Delete("DynamicalCode.dll");

클 라 이언 트 의 입력 프로그램 에 대해 서 는 Marshalby RefObject 류 와 IRemoteInterface 인터페이스 에 계승 하고 RemoteAccess 프로그램 집합 에 대한 인용 을 추가 해 야 합 니 다.다음은 입력:

using System;

using System.Reflection;

using RemoteAccess;

 

namespace Dynamicly

{

    public class HelloWorld : MarshalByRefObject,IRemoteInterface

    {

        public object Invoke(string strMethod,object[] Parameters)

        {

            return this.GetType().InvokeMember(strMethod, BindingFlags.InvokeMethod,null,this,Parameters);

        }

 

        public string GetTime(string strName)

        {

            return  "Welcome " + strName + ", Check in at " + System.DateTime.Now.ToString();

        }

    }

}

그러면 적당 한 컴 파일,로드 와 마 운 트 해제 프로그램 집합 을 통 해 프로그램 이 항상 소 모 를 제어 할 수 있 는 과정 에 있 고 동적 컴 파일 의 목적 을 달성 할 수 있 습 니 다.또한 서로 다른 응용 프로그램 도 메 인 에서 자신의 프로그램 을 더욱 안전 하고 건장 하 게 하기 때 문 입 니 다.예시 코드 다운로드:http://xiazai.jb51.net/201311/yuanma/DynamicCompiler(jb51.net).rar

좋은 웹페이지 즐겨찾기