惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
J
Java Code Geeks
博客园 - 聂微东
量子位
C
Check Point Blog
T
The Blog of Author Tim Ferriss
T
Tailwind CSS Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
B
Blog
罗磊的独立博客
腾讯CDC
GbyAI
GbyAI
博客园 - 【当耐特】
A
About on SuperTechFans
M
MIT News - Artificial intelligence
U
Unit 42
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队

博客园 - 水随风

[翱捷报表]报表系统的文件设计 [原创]从中文智能提示到表达式识别与计算 [原创]通过Attribute完成中文智能提示 2008年秋季程序员流行色之Visual studio黑色幽默 [资料收集]Attributes in C# [资料收集]Unicode编码问题,编程方面的技巧集合 [小记]TFS看Team编辑状态的命令行 [日语]常用日语汇总(转) [原创]Jquery下的表单验证(二) [原创]在jquery下写的表单验证 - 水随风 - 博客园 [引用]城市编码 -PHP [原创]Repeater在代码中定义模板 [原创]Html静态页面生成类 [设计模式]Memento pattern(备忘录模式)在Paint.net中的应用 [资料收集]通过 C# 简化 APM [linux]安装过程 [资料收集]All about Unsafe Code in C# [原创]数据访问类 [原创]js获取天气预报
[原创]动态编译自定义代码
水随风 · 2008-08-27 · via 博客园 - 水随风

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

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

我们要完成一段自定义代码的行为,这些应用有很多,而且可以解决许多别扭的问题,比方说计算器的表达式,由用户随意制定某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|动态编译|自定义代码|代码|原创

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