.NET中的动态定制手段(Part 1)C#

王朝c#·作者佚名  2006-01-09
宽屏版  字体: |||超大  

总想抽点时间把前一段时间的研究成果写下来,现在终于可以了,.NET为我们提供了很多新的、好玩的功能,如果不用岂不是糟蹋了。

我对动态定制的定义是:在编写程序时(甚至在编译程序时)都不用定义自己所要用的东西,都在运行的时候来决定,甚至是在运行的时候‘动态的’将其生成。

脚本定制是其中之一。

下面介绍一种.NET下比较好用的脚本定制方法,它充分利用了.NET FrameWork提供的动态编译功能,代码量也非常小。效率也不低。比如(我不会举例子,瞎举一下,不要太在意)我实现了一个装载MyClass的容器MyContainer,我考虑到需要对添加MyClass的方法MyContainer.Add加以限制,比如有MyClass A了,就不可以

向MyContainer中添加MyClass B了。如果我硬编码,那么如果限制改变了(比如A、B可以共存了,而A、C不能共存了),那么我的代码就必须进行改变(其实就是改几行代码再重新编译一遍,也没什么麻烦的),但是首先程序是不能再运行了,必须重启。但是如果你是使用脚本来进行校验的,你可以让你的程序监控着脚本文件,如果脚本发生改变,就重新编译脚本,对程序进行动态改变,那么你的程序就不必重启,也不必重新编译(但是你必须作出抉择,容器中的内容未必是‘安全’的了,因为限制改了,过去是正确的现在则未必了,容器至少要清空)。

那么对这个问题怎么进行脚本定制呢?

我的方案如下:(借鉴自Netron Graphlib)

首先,定义一个接口IScript,

public interface IScript

{

void Intialise(MyContainer m);

bool Check(MyObject o);

}

接着是在MyContainer.Add中加几行代码

public int Add(MyObject o)

{

CodeDomProvider provider = null;

provider = new Microsoft.CSharp.CSharpCodeProvider();//.NET起码提供了C#和VB.NET的编译器,

//可能还有第三方提供的,我不知道。

//这一部分可以用FactoryMethod

//我只是演示就直接用C#了

ICodeCompiler compiler = provider.CreateCompiler(); //得到编译器

CompilerParameters parms = new CompilerParameters();

CompilerResults results = null;

//配置编译参数

parms.MainClass="Script";

parms.GenerateExecutable = false;

parms.GenerateInMemory = true;

parms.TempFiles=new TempFileCollection(Path.GetTempPath(),false);

parms.IncludeDebugInformation = false;

parms.ReferencedAssemblies.Add("System.dll"); //添加引用

foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())

{

parms.ReferencedAssemblies.Add(asm.Location);

}

TextReader reader = File.OpenText(“CheckScript.cs“);//当然,可以读取配置,也可以监控,我就不写了

string Source = reader.ReadToEnd();

results = compiler.CompileAssemblyFromSource(parms, Source);

Assembly ass = results.CompiledAssembly;

foreach(Type type in ass.GetTypes())

{

if(type is IScripter)

{

IScript Checker = ass.CreateInstance(type.FullName);

Checker.Intialise(this);

if(!Checker.Check(o)) return; //累死我了,就不写得更漂亮些了

}

}

//代码部分

}

脚本示例如下(CheckScript.cs)

using System;

using System.Diagnostics;

using MyNameSpace;

namespace MyNameSpace.Scripts

{

public class Script: IScript , System.IDisposable

{

private static int counter = 0; //计数器

MyContainer m;

public void Initialize( MyContainer m)

{

this.m= m;

}

public bool Check(MyObject o)

{

//随你喜欢的代码,一定要返回啊!不然会出异常的!

}

#region "IDisposable implementation"

public virtual void Dispose()

{

Dispose( true );

System.GC.SuppressFinalize( this);

}

public virtual void Dispose( bool disposing )

{

if ( ( disposing ) )

{

// Free other state (managed objects).

}

// Free your own state (unmanaged objects).

// Set large fields to null.

}

~Script()

{

// Simply call Dispose(false).

Dispose( false );

}

#endregion

}

}

全加在一块,不过二十几行程序,还是比较实用的,至于效率,只要设计得合理,只有在载入时才会编译脚本,其余时候与正常程序并无二样,而且如果设计得好的话,可以动态支持多种脚本,加上第三方提供的编译功能,真是太方便了。建议使用在特别容易改变规则的地方,缺点就是底层代码直接就可以被别人看到,对脚本的修改不适当(尤其是别有用心的修改)的话,程序很容易崩溃。所以建议只用来定制限制和校验。简单多变的服务就不要用了吧。至于的动态定制,下回再说。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有