2013-02-27 3 views
1

System.CodeDom.Compiler을 사용하여 코드를 즉석에서 컴파일합니다. 컴파일 된 소스 안의 모든 것이 잘 작동합니다.'소스에서 컴파일 된 어셈블리'에서 '호스트'콜백 호출

o = results.CompiledAssembly.CreateInstance("Foo.Bar"); 
MethodInfo mi = o.GetType().GetMethod("SayHello"); 
mi.Invoke(o, null); 

을하지만이 전 비동기 WebClient.DownloadStringAsync를 사용하여 문자열을 검색하는 웹 클라이언트를 사용하고 가정 해 봅시다 : 내 함수를 호출하는 방법을 알고있다. 또는 컴파일 된 소스에서 호스트에 "이봐, 나는 너를 위해 좋은 문자열을 준비했다." 예를 들어, WebBrowser를 사용했습니다. 기본적으로, 나는 두 개의 인스턴스 각각을 다루는 방법을 안다 : 나의 호스팅 프로그램과 컴파일 된 프로그램이지만, 컴파일 된 프로그램이 호스트와 통신하기를 원한다. 그건 그렇고, 난 슈퍼 실험 프로그래머가 아니므로, 명백한 방법이 내 마음에 온다.

내가 시도한 것 :

1. 시도 할 필요가 없지만 컴파일 된 소스에서 문자열 스택이나 태스크 큐를 읽는 타이머를 사용할 수는 있지만 응용 프로그램의 목적은 사실적인 태스크를 실행할 수있는 +/- 60 개의 스크립트를 갖는 것입니다. 연속적인 백그라운드 프로세스가 아니기 때문에 CPU에서 효율적이지 않습니다.

2. 나는 호스팅 응용 프로그램에있는 것처럼 컴파일 된 소스에 핸들러를 전달했습니다.

//In the hosting app 
    MethodInfo mi2 = o.GetType().GetMethod("attachCallbackToHost"); 
    mi2.Invoke(o2, new object[] { new WebBrowserNavigatedEventHandler (wb_navigated) }); 

    //... And the handler 
    public static void wb_navigated(object sender, WebBrowserNavigatedEventArgs e) 
    {    
     string browserHtmlFromCompiledSource = ((WebBrowser)sender).DocumentText; 
     MessageBox.Show(browserHtmlFromCompiledSource); 
    } 

    // Plain text from the compiled source code 
    public void attachCallbackToHost(WebBrowserNavigatedEventHandler handlerFromTheHost) 
    { 
     wb.Navigated += handlerFromTheHost; 
    } 

그리고 아무 것도하지 않았습니다.

3. 어쩌면 클래스 나 변수를 컴파일 된 어셈블리에 전달하여 공유 할 수 있습니까?

그래서, 질문 중 하나이 또는 다른입니다

  • 어떻게 컴파일 된 프로그램 내부의 특정 변수 나 속성 내부 변화를 효율적으로보고?

  • 호스트에 콜백을 연결하는 방법은 무엇입니까?

+0

Q3에 관해서는, 당신은 임시 파일을 사용할 수 있으며 된 CodeDom 컴파일러에 디버그 스위치를 추가 :

여기에 엄격하게 내 질문에 아무것도 더 응답 전체 코드입니다. – leppie

+0

왜 임시 파일과 디버그 스위치가 필요합니까? 나는 (1) 컴파일 된 소스에서 변수가 변경되었음을 통보 받거나 (2) '호스트'프로그램에서 호출 된 콜백을 원합니다. 지금 당장은 컴파일 된 프로그램이 호스트 어셈블리에 액세스 할 수있는 방법을 찾고 있으므로 함수에 액세스하기 위해 네임 스페이스를 따라갈 것입니다. –

+0

당신의 대답에 따라, 나는 질문을 오해 한 것 같습니다. (해결을 위해 +1하고 대답을 게시하십시오.) – leppie

답변

1

확인. 컴파일 된 소스에서 호스트에 액세스하는 데 필요한 유일한 것은 컴파일러 매개 변수에 대해 참조 어셈블리에 호스트 어셈블리를 추가하는 것입니다 : 나는 그것을 가지고

compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); 

그래서 특별한 콜백 또는 INotifier에 대한 필요가 없습니다 .

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using Microsoft.CSharp; 
using System.CodeDom.Compiler; 
using System.Reflection; 

namespace MamaProgram 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      string source = 
      @" 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Net; 
using MyMama = MamaProgram;    
namespace Baby 
{ 
    public class Program 
    { 
     public WebBrowser wb = new WebBrowser();   

     public void navigateTo(string url) 
     { 
      wb.Navigated += wb_navigated;    
      wb.Navigate(url);    
     } 

     public void wb_navigated(object sender, WebBrowserNavigatedEventArgs e) 
     {    
      MyMama.Form1.getResult(wb.DocumentText);    
     } 
    } 
} 
      "; 

      Dictionary<string, string> providerOptions = new Dictionary<string, string> 
       { 
        {"CompilerVersion", "v3.5"} 
       }; 

      CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions); 

      CompilerParameters compilerParams = new CompilerParameters 
      { 
       GenerateInMemory = true, 
       GenerateExecutable = false, 
       TreatWarningsAsErrors = false     
      }; 

      compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); 
      compilerParams.ReferencedAssemblies.Add("System.Data.dll");    
      compilerParams.ReferencedAssemblies.Add(typeof(System.Linq.Enumerable).Assembly.Location); // Trick to add assembly without knowing their name    
      compilerParams.ReferencedAssemblies.Add(typeof(System.ComponentModel.Component).Assembly.Location); // Trick to add assembly without knowing their name       
      compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll"); 
      CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source); 

      if (results.Errors.Count != 0) 
       throw new Exception("Compilation failed"); 

      object o = results.CompiledAssembly.CreateInstance("Baby.Program"); 
      MethodInfo mi2 = o.GetType().GetMethod("navigateTo"); 
      mi2.Invoke(o, new object[] { "http://www.google.com" });       
     } 

     public static void getResult(string result) 
     { 
      MessageBox.Show(result); 
     }   
    } 
}