1

我正在使用System.CodeDom.Compiler. 编译后的源代码中的所有内容都运行良好,无论我在此源代码中放入什么。我知道如何调用我的函数:

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

但是假设我正在使用 WebClient 使用 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. 也许我可以通过将类或变量传递给已编译的程序集来共享它?

所以,问题是这个或另一个:

  • 如何有效地观察编译程序中特定变量或属性的变化?

  • 如何将回调附加到主机?

4

1 回答 1

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);
        }        
    }
}
于 2013-02-27T19:31:45.933 回答