这篇文章给大家介绍。net中的动态编译技术是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
代码的动态编译并执行是一个。净平台提供给我们的很强大的工具用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码来扩展我们已有的应用程序。这在很大程度上给我们提供了另外一种扩展的方式(当然这并不能算是严格意义上的扩展,但至少为我们提供了一种思路)。
动态代码执行可以应用在诸如模板生成,外加逻辑扩展等一些场合。一个简单的例子,为了网站那的响应速度,HTML静态页面往往是我们最好的选择,但基于数据驱动的网站往往又很难用静态页面实现,那么将动态页面生成HTML的工作或许就是一个很好的应用场合。另外,对于一些模板的套用,我们同样可以用它来做。另外这本身也是插件编写的方式。
<强> 强>
. NET为我们提供了很强大的支持来实现这一切我们可以去做的基础,主要应用的两个命名空间是:System.CodeDom.Compiler和Microsoft.CSharp或Microsoft.VisualBasic。另外还需要用到反射来动态执行你的代码。动态编译并执行代码的原理其实在于将提供的源代码交予CSharpCodeProvider来执行编译(其实和CSC没什么两样),如果没有任何编译错误,生成的IL代码会被编译成DLL存放于于内存并加载在某个应用程序域(默认为当前)内并通过反射的方式来调用其某个方法或者触发某个事件等。之所以说它是插件编写的一种方式也正是因为与此,我们可以通过预先定义好的借口来组织和扩展我们的程序并将其交还给主程序去触发。一个基本的动态编译并执行代码的步骤包括:
·,,,,,,,,将要被编译和执行的代码读入并以字符串方式保存
·,,,,,,,,声明CSharpCodeProvider对象实例
·,,,,,,,,调用CSharpCodeProvider实例的CompileAssemblyFromSource方法编译
·,,,,,,,,用反射生成被生成对象的实例(Assembly.CreateInstance)
·,,,,,,,,调用其方法
以下代码片段包含了完整的编译和执行过程:
代码如下:
//得到的代码编译
字符串strSourceCode=this.txtSource.Text;
//1。创建一个新的CSharpCodePrivoder实例
CSharpCodeProvider objCSharpCodePrivoder=new CSharpCodeProvider ();
//2。装箱后的参数设置运行时编译一个新的CompilerParameters实例
CompilerParameters objCompilerParameters=new CompilerParameters ();
objCompilerParameters.ReferencedAssemblies.Add (“System.dll");
objCompilerParameters.ReferencedAssemblies.Add (“System.Windows.Forms.dll");
objCompilerParameters。GenerateInMemory=true;
//3。CompilerResults: Complile通过调用一个方法的代码片段从提供者
CompilerResults cr=objCSharpCodePrivoder。CompileAssemblyFromSource (objCompilerParameters strSourceCode);
如果(cr.Errors.HasErrors)
{
,,,字符串strErrorMsg=cr.Errors.Count.ToString () +“;错误:“;
,,,for (int x=0;x & lt;cr.Errors.Count;x + +)
,,,{
,,,,,,,strErrorMsg=strErrorMsg +“\ r \在线:“+
,,,,,,,,,,,,,,,,,,,,cr.Errors [x] .Line.ToString () +“;——“;+
,,,,,,,,,,,,,,,,,,,,cr.Errors [x] .ErrorText;
,,,}
,,,this.txtResult。文本=strErrorMsg;
,,,MessageBox.Show(“有构建论述,请修改代码!”,“编译Error");
,,,返回;
}
//4。使用反射调用方法
组装objAssembly=cr.CompiledAssembly;
对象objClass=objAssembly.CreateInstance (“Dynamicly.HelloWorld");
如果(objClass==null)
{
,,,this.txtResult。文本=按砦?“+“简直# 39;t负载类干净;
,,,返回;
}
object [] objCodeParms=新对象[1];
objCodeParms[0]=鞍?”;strResult=
字符串(string) objClass.GetType () .InvokeMember (
,,,,,,,,,,“GetTime" BindingFlags。InvokeMethod, null, objClass objCodeParms);
this.txtResult。文本=strResult;
需要解释的是,这里我们在传递编译参数时设置了GenerateInMemory为真,这表明生成的DLL会被加载在内存中(随后被默认引用入当前应用程序域)。在调用取得时间方法时我们需要加入参数,传递对象类型的数组并通过反射的InvokeMember来调用。在创建生成的组装中的对象实例时,需要注意用到的命名空间是你输入代码的真实命名空间。以下是我们输入的测试代码(为了方便,所有的代码都在外部输入,动态执行时不做调整):
代码如下:
使用系统;
名称空间构建
{
,,,公开课HelloWorld