代码改变世界

[原创]动态编译自定义代码

2008-08-27 16:02  水随风  阅读(545)  评论(0编辑  收藏  举报

 

由于园子里的朋友已经有过很多了,我在这里也算是老话重提,用一个比较简单的应用来阐述一下这个事。一方面这个用法在项目中应用到了,一方面也是一个知识的总结

 

我们首先来理清一下我们要做的事情和思路

我们要完成一段自定义代码的行为,这些应用有很多,而且可以解决许多别扭的问题,比方说计算器的表达式,由用户随意制定某Button的事件行为。

 

 

using System.CodeDom.Compiler;

那么要完成这样的东西我们需要什么呢?

我们需要引用以下命名空间 

 

Compiler提供了动态编译C#的处理,就像如下这样的代码

 

Code

 

那么我们的思路就出来了

1. .NET前,首先要做的就是把必须要引用的DLL引用好嘛,动态编译类也不例外

2. 我们首先需要将你的代码放入一个Class,这个Class你可以随意定义(最好特别一点,免得冲突),放在一个Class的目的是,编译的时候是以一个Class来编译的,长这么大没看见只编译方法的编译器,呵呵

3. 动态编译我们写出来的代码(因为编译出来后会以DLL形式存在)

4. 利用反射加载这个DLLAssembly

5. 创建你所制定的那个Class实例后,直接可以调用你所要使用的方法

 

好的,以上是思路,下面我们用简单的代码来理解一下这个过程

 

 

首先我们写好一个方法,用于准备所需要的动态引用

Code

 

首先我们要定义一个Class,这个Class就是你准备动态编译的Class,我们取名叫做DynamicClass,记住一定要把引用添加上

string CLASS_BODY=
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
Public 
class  DynamicClass
{
//这里可以塞你想塞的事件,方法和属性
……
                Public 
void Add(int a,int b)
{
//这里就是我想要完成的动态处理
    ……
}
}";

 

 

这个Class就是我们要动态编译的Class,那么我们再看一下如何去生成他,上面我们提到的编译代码加下工:

Microsoft.CSharp.CSharpCodeProvider CsharpProvider = new Microsoft.CSharp.CSharpCodeProvider();

//创建CSharp编译器的对象

ICodeCompiler CSCompiler= CsharpProvider.CreateCompiler();

//编译时要用到的参数

CompilerParameters param = new CompilerParameters();

param.OutputAssembly = dllRelativePath;//这个路径,你可以指定到你想输出的路径,也可以使用默认的路径,并在之后反射的代码中访问这个属性得到路径

param.GenerateExecutable = false;

param.GenerateInMemory = true;

//在编译前还要将以前提到到的GetReferencedAssemblies ()方法把需要的引用加上

StringCollection  ReferencedAssemblies  = GetReferencedAssemblies ();

for (int i = 0; i < ReferencedAssemblies.Count; i++)

{

        param.ReferencedAssemblies.Add(ReferencedAssemblies[i]);

 }

//执行这句话后会生成CompilerResults的一个结果

CompilerResults res = CompileAssemblyFromSource(param, code);

 

在获取编译结果后,我们要验证一下是否生成成功了,不然我们此后的代码就调不到了

Assembly retValue = null;

            if (res.Errors.HasErrors)

            {

               //如果错误,这里爆出错误信息

            }

            else

            {

                retValue = res.CompiledAssembly;

            }

return retValue;

以上的过程就是一段自定义的代码用代码生成Assembly的过程,当然如果文件存在你可以简单的用Assembly.LoadFile方法,简单的说,只是操作Assembly创建实例而已

 

最后的关键时刻来了,我们之前写了那么多代码就是为了现在能够访问到自己定义的动态代码

Object DynamicClassObject  = Activator.CreateInstance( GetObject<Type>( "DynamicClassType",delegate(){

// TempAssembly就是上面return回来的CompiledAssembly

                    if (this.TempAssembly!=null)

                    {

                        return this.TempAssembly.GetType("DynamicClass", false);

                    }

                    else

                    {

                        return null;

                    }

                }););

 

你可以用以下代码调到前面的DynamicClassAdd方法

MethodInfo AddHandlersInfo = this.DynamicClassType.GetMethod(Add);

//Invoke(object obj, object[] parameters);方法调用

//

// DynamicClassObject创建的实例

// param方法的参数

AddHandlersInfo. Invoke(DynamicClassObject ,param)

 

 

上面讲的很粗略,我尽可能写清楚,没办法,表达能力有限,哈哈

 

===========================================================================

waterlion|动态编译|自定义代码|代码|原创

===========================================================================