利用CodeDom和反射动态编译并执行程序集
动态编译,听起来很酷,不是吗?
1. 什么是动态编译
所谓动态编译是由两个字组成的:动态+编译。很显然,我们是想实现临时地给出一段代码,然后将其编译成程序集(可以是在内存中,也可以是输出一个真正的dll)
2. 什么时候需要用到动态编译?
呃,这个问题有点难,简单地说,就是要动态的时候啦。呵呵。我们有的时候需要提供系统这么一种灵活性,即有的类型没有办法预先写好,而是要根据情况动态编译。这么说吧,例如我们希望根据数据库里面一个表的结构,动态编译出来一个对应的类型。
3. 如何使用动态编译。下面是一个很简单的例子
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();//得到一个CSharp的编译器
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.ReferencedAssemblies.Add("system.data.dll");
cp.ReferencedAssemblies.Add("system.xml.dll");
cp.GenerateExecutable = false;//这是指示说我们输出的程序集是dll,而不是exe
cp.GenerateInMemory = true; //这是指示在内存中创建该程序集
StringBuilder sb = new StringBuilder();
sb.Append("using System; \n");
sb.Append("public class MyClass{");
sb.Append("public string HelloWorld(){");
sb.AppendFormat("return {0};", "\"Hello,world\"");
sb.Append("}}"); //这里为止,我们构造了一个动态的类型,它有一个方法是HelloWorld
CompilerResults result = compiler.CompileAssemblyFromSource(cp, sb.ToString()); //执行编译
object _compilerobject = result.CompiledAssembly.CreateInstance("MyClass");
MethodInfo method = _compilerobject.GetType().GetMethod("HelloWorld");
Console.WriteLine(method.Invoke(_compilerobject, null).ToString());
Console.Read();
}
}
我们还可以将编译的结果保存为一个真正的dll。且看下面的代码修改
cp.GenerateInMemory = false;
cp.OutputAssembly = "C:\\temp.dll";
有的朋友可能会疑惑,如果GenerateInMemory为true的话,是不是就真的不会有程序集产生呢?其实不然,其实它仍然会有一个临时的dll,在%temp%目录下面,只不过使用完之后就被删除了。