2. 编译源代码
编译源代码相当简单,只需一条语句就搞定了: CompilerResults compilerResults = compiler.CompileAssemblyFromSource(this.theParameters, this.SourceText);
执行后,可以从compilerResults取得以下内容:
NativeCompilerReturnValue | 编译结果,用于检查是否成功 | Errors | 编译时产生的错误和警告信息 | CompiledAssembly | 如果编译成功,则返回编译生成的Assembly |
示例函数: /**//// <summary> /**//// <summary> /// 编译脚本。编译前将清空以前的编译信息。 /// CompilerInfo将包含编译时产生的错误信息。 /// </summary> /// <returns>成功时返回True。不成功为False。</returns> public bool Compile() { this.theCompilerInfo = ""; this.isCompiled = false; this.theCompiledAssembly = null; // 下面一行代码仅用于.NET 2.0 this.theCompilerResults = this.theProvider.CompileAssemblyFromSource(this.theParameters, this.SourceText); // 下面一行代码用于.NET1.1(与.NET2.0的区别是,.NET2.0不需要调用CreateCompiler) // this.theCompilerResults = this.theProvider.CreateCompiler().CompileAssemblyFromSource(this.theParameters, this.SourceText); if(this.theCompilerResults.NativeCompilerReturnValue == 0) { this.isCompiled = true; this.theCompiledAssembly = this.theCompilerResults.CompiledAssembly; } System.Text.StringBuilder compilerInfo = new System.Text.StringBuilder(); foreach(CompilerError err in this.theCompilerResults.Errors) { compilerInfo.Append(err.ToString()); compilerInfo.Append("/r/n"); } theCompilerInfo = compilerInfo.ToString(); return isCompiled; } |
3. 执行代码 使用Reflection机制就可以很方便的执行Assembly中的代码。 我们假设编译时使用的脚本代码 this.SourceText 内容如下: namespace test { public class script { public static void Main() { MessageBox.Show("Hello"); } } } |
则相应的执行代码为:
scriptEngine.Invoke("test.script", "Main", null);
注意:Invoke调用的函数必须是静态的。 Invoke函数内容: /**//// <summary> /// 执行指定的脚本函数(Method)。 /// 如果指定的类或模块名,以及函数(Method)、或参数不正确,将会产生VsaException/VshException例外。 /// </summary> /// <param name="__strModule">类或模块名</param> /// <param name="__strMethod">要执行的函数(Method)名字</param> /// <param name="__Arguments">参数(数组)</param> /// <returns>返回执行的结果</returns> public object Invoke(string __strModule, string __strMethod, object[] __Arguments) { if(!this.IsCompiled || this.theCompiledAssembly == null) throw new System.Exception("脚本还没有成功编译"); Type __ModuleType = this.theCompiledAssembly.GetType(__strModule); if(null == __ModuleType) throw new System.Exception(string.Format("指定的类或模块 ({0}) 未定义。", __strModule)); MethodInfo __MethodInfo = __ModuleType.GetMethod(__strMethod); if(null == __MethodInfo) throw new System.Exception(string.Format("指定的方法 ({0}::{1}) 未定义。", __strModule, __strMethod)); try { return __MethodInfo.Invoke(null, __Arguments); } catch( TargetParameterCountException ) { throw new System.Exception(string.Format("指定的方法 ({0}:{1}) 参数错误。", __strModule, __strMethod)); } catch(System.Exception e) { System.Diagnostics.Trace.WriteLine(string.Format("执行({0}:{1})错误: {2}", __strModule, __strMethod, e.ToString())); return null; } } |
总结: CodeDom可以很方便的随时编译源代码,并动态执行。虽然作为脚本引擎,它没有VsaEngine正规和方便,但作为一般应用,也够用了。并且结合Reflection机制,它的功能比VsaEngine更强大:它可以编译任何提供CompilerProvider的CLR语言(目前.NET自带的语言中都有)。 当然,它也有一些缺点:它生成的Assembly不能动态卸载。这在一般情况下不成问题,因为一个源代码只需编译一次,并载入执行,并不需要动态卸载。 假如你需要做脚本编辑器时,就要考虑这个问题,因为有可能一个脚本会因为修修改改而不停的重新编译,从而造成不停的产生新的Assembly,最后将导致内存被大量占用。要解决这个问题,需要将编译器加载到独立的AppDomain中,通过卸载AppDomain达到卸载所需的Assembly的目的。
 
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |