string code = null;// 1. 生成要编译的代码。(示例为了简单直接从程序集内的资源中读取)Stream stram = typeof(CodeDOM).Assembly .GetManifestResourceStream("TestOptimizeReflection.用户手册.txt");using( StreamReader sr = new StreamReader(stram) ) { code = sr.ReadToEnd();}//Console.WriteLine(code);// 2. 设置编译参数,主要是指定将要引用哪些程序集CompilerParameters cp = new CompilerParameters();cp.GenerateExecutable = false;cp.GenerateInMemory = true;cp.ReferencedAssemblies.Add("System.dll");cp.ReferencedAssemblies.Add("OptimizeReflection.dll");// 3. 获取编译器并编译代码// 由于我的代码使用了【自动属性】特性,所以需要 C# .3.5版本的编译器。// 获取与CLR匹配版本的C#编译器可以这样写:CodeDomProvider.CreateProvider("CSharp")Dictionarydict = new Dictionary ();dict["CompilerVersion"] = "v3.5";dict["WarnAsError"] = "false";CSharpCodeProvider csProvider = new CSharpCodeProvider(dict);CompilerResults cr = csProvider.CompileAssemblyFromSource(cp, code);// 4. 检查有没有编译错误if( cr.Errors != null && cr.Errors.HasErrors ) { foreach( CompilerError error in cr.Errors ) Console.WriteLine(error.ErrorText); return;}// 5. 获取编译结果,它是编译后的程序集Assembly asm = cr.CompiledAssembly;
整个过程分为5个步骤,它们已用注释标识出来了,这里不再重复了。
如何调用编译结果
前面的代码把一段文本字符串编译成了程序集,现在还有最后一个问题:如何调用编译结果?
答案:有二种方法,
1. 直接调用方法。2. 实例化程序集中的类型,以接口方式调用方法。其实这二种方法都需要使用反射,用反射定位到要调用的类型和方法。第一种方法要求在生成代码时,生成的类名和方法名是明确的,在调用方法时,我们有二个选择:
1. 用反射的方式调用(这里只是一次反射)。2. 为方法生成委托(用介绍的方法),然后基于委托调用。第二种方法要求在生成代码时,首先要定义一个接口,保证生成的代码能实现指定的接口,
然而用反射找到要调用的类型名称,用反射或者委托调用构造方法创建类型实例,最后基于接口去调用。我们熟悉的ASPX页面就是采用了这种方式来实现的。这二种方法也可以这样区分:
1. 如果生成的方法是静态方法,应该选择第一种方法。2. 如果生成的方法是实例方法,那么选择第二种方法是合理的。对于前面的示例,我采用了第一种方法了,因为类名和方法名称都是事先确定的而且实现起来比较简单。
// 6. 找到目标方法,并调用Type t = asm.GetType("OptimizeReflection.用户手册");MethodInfo method = t.GetMethod("Main");method.Invoke(null, null);
参考:http://www.cnblogs.com/fish-li/archive/2013/02/24/2924673.html#_labelStart