用.Net的动态代码生成功能实现AOP

随着AOP的概念被越来越多的讨论,动态代码生成技术也正受到更多人的重视。动态代码生成可以分为动态生成源代码、动态生成中间代码、动态生成机器码等几个层次。动态生成源代码最为简单,各种WEB开发环境都可以理解为这一层次,例如,用ASP很容易写出如下代码:

< % Response.Write  " <script>alert('hello world');</script> "  % >

而动态生成中间代码或机器代码则要复杂得多,一般来说很难人工完成,大多数情况都有借助专门的库或工具来完成。ATL中有个小thunk的东东,就是这种想法的一个应用:它通过动态生成机器码完成了窗口消息处理之前从HWND到窗口类指针的转换,从而免去了从长长的列表中查找指定的类的过程(参见《深入解析ATL》中文版第410页)。而在JAVA和.Net这样的托管环境下,类似于C++的直接向内存中写机器码的方法变得不怎么现实,取而代之的是使用运行环境本身为我们提供的动态代码生成的方法。
.Net提供了Emit和CodeDOM两种方式用于动态生成代码,前一种方式用于生成可以即时执行、即时保存成二进制文件的机器码,后一种方式更多的适合于生成人能读懂的源代码。我在这里主要使用了Emit方式。
我的目标是这样的:仿照Spring中AOP的思想,通过动生成类代码,实现指定类的动态代理,从而可以对指定的方法实行运行时的拦截。例如:

     public   interface  MyInterface
    
{
        
void Say(String name);
    }


    
public   class  MyClass: MyInterface
    
{
        
public void Say(String name)
        
{
            Console.WriteLine(
"大家好,我是" + name);
        }

    }

类MyClass实现了接口MyInterface,在其方法Say中向屏幕输出一字符串。下面的测试程序很容易验证程序在正常工作:

    MyInterface inst  =   new  MyClass();
    inst.Say(
" Billy " );

我现在要做的是,在调用方法Say之前和之后做一些事,也就是说要拦截方法Say的调用,并且尽可能少的修改用户代码,从而,在用户看来,他的类和接口的定义是不变的,他仍然是调用MyInterface的一个实例inst上的方法,但在调用的时候我已经可以有所察觉。简单的思想就是用户调用Say的时候实际上调用的是另一个方法,而在这个方法中再去调用真正的MyClass::Say()。
若要让用户仍在MyInterface这个接口下声明变量,并且调用的是另一个方法,能完成此工作的方式就是使用多态,也就是方法的晚绑定:

     public   class  MyClass2: MyClass  { ... }

但这样做会遇到一个在JAVA世界中不存在的问题,就是除非声明了virtual,否则C#的函数是早绑定的,在子类中不能重写没有被声明为virtual的方法。而之前我说过,我要尽量少的让用户修改代码,特别是类和接口声明是不要修改的,所以这里我决定让我的类不继承于MyClass,而是让它直接实现MyInterface接口,从而它和MyClass类成为了兄弟:

     public   class  MyClass2: MyInterface
    
{
        
private MyClass c = new MyClass();
        
public void Say(String name)
        
{
            
//Do something
            c.Say(name);
            
//Do something
        }

    }

我要实现的最终结果是这样的,但问题很明显,这段代码谁来写?总不能让用户再为每个想使用AOP的类都写这样的代码吧。使用工具来自动生成源代码?也不是个好主意。那么最好的方式就是在运行时根据接口MyInterface来动态产生这样一个代理类,并且提供一个工厂,当用户想要生成新的MyClass对象时,我的程序来接管这部分工作,我先生成MyClass和MyClass2两个类的实例c1和c2,并且把c1作为c2的一个成员变量;动态为MyClass2类生成所有的MyInterface接口方法的实现,在实现中都是调用c1的相应的方法,最后把c2以接口MyInterface的身份返回给用户,用户代码变成了这样:

    MyInterface inst  =  DynamicProxyBuilder.GetProxyObject < MyInterface, MyClass > ();
    inst.Say(
" Billy " );

这里我使用了C# 2.0提供的泛型功能,从而免去了返回对象的类型转换,当然如果使用C# 1.x,只要稍做改动就可以了。
DynamicProxyBuilder是我专门用来生成动态代理的类,GetProxyObject是它唯一的公共方法:

         public   static  InterfaceType GetProxyObject < InterfaceType, BaseType > ()
        
{
            Type interfaceType 
= typeof(InterfaceType);
            Type baseType 
= typeof(BaseType);

            
//取得代理类的动态类型,如果不存在,就创建它
            Type targetType = GetProxyType(interfaceType, baseType);

            
//创建代码对象和被代理对象的实例,并且返回代理对象
            return (InterfaceType)Activator.CreateInstance(targetType, Activator.CreateInstance(baseType));
        }


其功能是返回一个实现了接口InterfaceType的能代理BaseType类型对象的对象,而这个对象类型,就是前面所说的MyClass2类型。这个MyClass2类是在编译阶段不存在的,它在第一次被请求时动态生成,生成的方式是调用DynamicProxyBuilder类的GetProxyType方法:

         private   static  Type GetProxyType(Type interfaceType, Type baseType)
        
{
            
// 这里省略了各种有效性检查

            
//动态类型的名称,也就相当于前面说的MyClass2
            String proxyClassName = "_dynamicproxy." + baseType.FullName + "Proxy";

            
if (!typeList.ContainsKey(proxyClassName)) //检查所请求类型是否已经生成了
            
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
【基本说明】 1、能够生成三层工厂模式操作的所有基本代码,简单的数据库操作。 2、生成的代码包括了 MODEL、BLL、Factory、IDAL、DAL、DBHelper、Config 生成的代码内有详细注释可提供参考。 3、提供数据库增、删、改、查、分页及其事务,并提供多种重载方式。 4、所有数据表必须有主键且主键是第一列,这个主要是为了保证获取记录和分页获取的统一性,其实可以取消这个规则。 6、建议新建App_Code文件夹将生成的C#代码放里面。见此文件夹直接拷贝到项目下既可以使用。 7、不保证所提供软件或程序的完整性和安全性。 8、请在使用前查毒 (这也是您使用其它网络资源所必须注意的) 。 9、《Coder(ASP.NET代码生成器)》需要.Net FrameWork2.0运行环境,基于SQL Server 2005使用。 10、如无法运行本软件,请下载并安装由微软公司提供的.Net FrameWork2.0系统. 11、如果您在使用过程中遇到程序问题或建议请于我联系我的Email是 mailto:[email protected]。 【生成单层代码】 输入数据库名(Server)登录名(Name)密码(Pwd),连接后选择库名(Database)表名(Tables) 之后单击'生成单层代码'新建App_Code文件夹将生成的C#代码(ASP.NET后台代码)放里面, 【生成三层工厂模式项目】 (1)B/S架构: 输入数据库名(Server)登录名(Name)密码(Pwd)连接数据库成功后直接点生成整个项目选择路径确定就好了。 (2)C/S架构: 输入数据库名(Server)登录名(Name)密码(Pwd)连接数据库成功后直接点生成整个项目选择路径确定, 生成项目后打开该项目解决方案将表示层删掉, 再单击vs的(文件→添加→新建项目→选择Windows应用程序),这样就生成C/S架构的程序了!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值