利用CodeDom和反射动态编译并执行程序集

时间:2023-02-20 21:36:15

动态编译,听起来很酷,不是吗?

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";

利用CodeDom和反射动态编译并执行程序集

有的朋友可能会疑惑,如果GenerateInMemory为true的话,是不是就真的不会有程序集产生呢?其实不然,其实它仍然会有一个临时的dll,在%temp%目录下面,只不过使用完之后就被删除了。

利用CodeDom和反射动态编译并执行程序集