我正在使用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脚本能够执行ponctual任务,而不是连续的后台进程,因此在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 :(得分: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);
}
}
}