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") Dictionary<string, string> dict = new Dictionary<string, string>(); 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