如何在.NET中实现脚本引擎

Python019

如何在.NET中实现脚本引擎,第1张

1. 构造一个编译器

设置编译参数

编译参数需要在CompilerParameters设置:

CompilerOptions用于设置编译器命令行参数

IncludeDebugInformation用于指示是否在内存在生成Assembly

GenerateInMemory用于指示是否在内存在生成Assembly

GenerateExecutable用于指示生成的Assembly类型是exe还是dll

OutputAssembly用于指示生成的程序文件名(仅在GenerateInMemory为false的情况)

ReferencedAssemblies用于添加引用Assembly

例如:

theParameters.ReferencedAssemblies.Add("System.dll")

创建指定语言的编译器

编译需要由指定语言的CodeDomProvider生成。

这里列举一些.NET的CodeDomProvider:

vb.net Microsoft.VisualBasic.VBCodeProvider

C#Microsoft.CSharp.CSharpCodeProvider

jscriptMicrosoft.JScript.JScriptCodeProvider

J#Microsoft.VJSharp.VJSharpCodeProvider

以C#为例,要创建C#编译器,代码如下:

//.NET 1.1/1.0

ICodeCompiler compiler = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler()

//.NET 2.0

ICodeCompiler compiler = (ICodeCompiler) new Microsoft.CSharp.CSharpCodeProvider()

下面是完整的创建编译器的例子:

/// <summary>

/// 创建相应脚本语言的编译器

/// </summary>

private void createCompiler(string strLanguage, bool debugMode, string strAssemblyFileName)

{

this.theParameters = new CompilerParameters()

this.theParameters.OutputAssembly = System.IO.Path.Combine(System.IO.Path.GetTempPath(), strAssemblyFileName + ".dll")

this.theParameters.GenerateExecutable = false

this.theParameters.GenerateInMemory = true

if(debugMode)

{

this.theParameters.IncludeDebugInformation = true

this.theParameters.CompilerOptions += "/define:TRACE=1 /define:DEBUG=1 "

}

else

{

this.theParameters.IncludeDebugInformation = false

this.theParameters.CompilerOptions += "/define:TRACE=1 "

}

AddReference("System.dll")

AddReference("System.Data.dll")

AddReference("System.Xml.dll")

strLanguage = strLanguage.ToLower()

CodeDomProvider theProvider

if("visualbasic" == strLanguage || "vb" == strLanguage)

{

theProvider = new Microsoft.VisualBasic.VBCodeProvider()

if(debugMode)

theParameters.CompilerOptions += "/debug:full /optimize- /optionexplicit+ /optionstrict+ /optioncompare:text /imports:Microsoft.VisualBasic,System,System.Collections,System.Diagnostics "

else

theParameters.CompilerOptions += "/optimize /optionexplicit+ /optionstrict+ /optioncompare:text /imports:Microsoft.VisualBasic,System,System.Collections,System.Diagnostics "

AddReference("Microsoft.VisualBasic.dll")

}

else if("jscript" == strLanguage || "js" == strLanguage)

{

theProvider = new Microsoft.JScript.JScriptCodeProvider()

AddReference("Microsoft.JScript.dll")

}

else if("csharp" == strLanguage || "cs" == strLanguage || "c#" == strLanguage)

{

theProvider = new Microsoft.CSharp.CSharpCodeProvider()

if(!debugMode)

theParameters.CompilerOptions += "/optimize "

}

//else if("jsharp" == strLanguage || "vj" == strLanguage || "j#" == strLanguage)

//{

//theProvider = new Microsoft.VJSharp.VJSharpCodeProvider()

//if(!debugMode)

//theParameters.CompilerOptions += "/optimize "

//}

else

throw new System.Exception("指定的脚本语言不被支持。")

this.theCompiler = theProvider.CreateCompiler()

}

/// <summary>

/// 添加引用对象。

/// </summary>

/// <param name="__strAssemblyName">引用的文件名</param>

public void AddReference(string __strAssemblyName)

{

theParameters.ReferencedAssemblies.Add(__strAssemblyName)

}

注:

在.NET Framework 2.0中,由于CreateCompiler方法被标记作废。为避免产生编译警告,可直接返回CodeDomProvider作为编译器:

this.theCompiler = (ICodeCompiler)theProvider

2. 编译源代码

编译源代码相当简单,只需一条语句就搞定了:

CompilerResults compilerResults = compiler.CompileAssemblyFromSource(this.theParameters, this.SourceText)

执行后,可以从compilerResults取得以下内容:

NativeCompilerReturnValue 编译结果,用于检查是否成功

Errors 编译时产生的错误和警告信息

CompiledAssembly 如果编译成功,则返回编译生成的Assembly

示例函数:

/// <summary>

/// 编译脚本。编译前将清空以前的编译信息。

/// CompilerInfo将包含编译时产生的错误信息。

/// </summary>

/// <returns>成功时返回True。不成功为False。</returns>

public bool Compile()

{

this.theCompilerInfo = ""

this.isCompiled = false

this.theCompiledAssembly = null

this.theCompilerResults = this.theCompiler.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

{

static public void Main()

{

MessageBox.Show("Hello")

}

}

}

则相应的执行代码为:

scriptEngine.Invoke("test.script", "Main", null)

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

}

}

脚本语言有javaScriptVBScript

其他的基本上不算脚本语言,

.NET 支持相当多的编程语言,C# C++ JAVA VB DELPHI......

但这些并非脚本语言,

它们都有自己的特性,可以用做WEB开发,也可用做应用程序开发.

ASP.NET 可以用C#或者VB JAVA等语言做开发语言.

浏览器端语言包括Ajax、CSS、JavaScript和VBScript语言。

ASP.NET通常可以使用三种脚本语言JavaScript、VBScript 还有一种就不晓得了。 。