转摘 https://www.cnblogs.com/niceWk/archive/2010/07/21/1782092.html

偷梁换柱

上一篇我们初试了DynamicAspect这把小刀,如果你已经下了源代码,你可以看看它在后台究竟做了什么手脚。如果你接触过一些动态的AOP组件,你也许已经发现大部分的实现都是在运行时通过反射机制重新创建一个代理对象或者装饰对象和适配器对象,其目的只有一个,把对目标方法的掉用转移到一个新建的方法上,所以DynamicAspect也不例外,那既然这样,你会问为什么还要重新发明车轮,其理由是目前动态编织的Aspect都有一个软肋,要么被编织的类不能是sealed的,也就是可以从它派生一个新的子类,要么需要为这个类定义一个接口,原因无非就是在开发代码的时候,类似下面的代码可以通过编译:

        Bank bank = Factory.Create<Bank>();
        bank.Deposit(100);

或者:

IBank bank = Factory.Create<Bank>();
            bank.Deposit(100);

感谢dynamic,在.NET 4中这个障碍突然之间说消失就消失了。第二个问题是取消这个限制真的很重要吗?很难回答,但个人认为如果任何实体都可以被编织(静态类除外)总是要比受这个限制那个限制要爽多多。其实,自从.NET4发布以来,我一直在看是否有人利用它的动态特性实现一个AOP,我没有看到,想来肯定是有人想到了,但还没有去做或者正在做也未必。

基于笔者多年对AOP的关注,所以决定尝试着开发一个,于是就有了DynamicAspect现在的原型。做一个动态的Aspect,基本上要解决下面的几个问题:

1、如何使调用对象方法的代码通过编译?

2、如何拦截对目标方法的调用?

3、哪些对象需要被编织?

4、对象的哪些方法被执行的时候需要被拦截?

5、如何定义方法中拦截点(Joinpoint)?

6、Aspect必须具备什么样的行为特征,以及它们如何匹配要编制的目标对象?

7、Aspect对象生命期的管理。

在探讨上面的几个问题之前,我想大致介绍一下dynamic这个大功臣,之所以这么说是因为如果没有dynamic也就没有DynamicAspect,甚至你把DynamicAspect看成是Dynamic技术和MEF技术二者结合的结晶一点也不为过,之所以大致介绍,因为完全的解释dynamic需要很大的篇幅,而且也超出了这个系列的主题范围,大家如果有兴趣可以自己阅读msdn文档相关部分和其他网友写的文章(笔者推荐Using the Dynamic Keyword in C# 4.0)。

近年来,动态语言火热流行,使得开发人员对生在静态语言家族的C#也有了支持动态的需求,C#3.0 引入Lambda 表达式,开始向支持动态迈进了一步,C#4.0引入dynamic又向前迈出了一大步,在这之前,.NET支持动态的表现是通过反射(相信有人使用反射来实现类似COM的迟后绑定),那么到底dynamic是什么?使用dynamic有什么好处?还是让代码来告诉我们吧,请看下面的代码:

            dynamic result = DoSomething(1, 2);

            result = DoSomething("Hello,", "Dynamic!");

DoSomething的方法如下:

static dynamic DoSomething(dynamic d1, dynamic d2)
        {
            return d1 + d2;
        }

结果第一个result返回:3

第二个result返回:Hello, Dynamic!

从上面的表达式看dynamic是一个CLR类型,所以几乎所有可以使用类型的地方都可以使用dynamic,但你不能通过new dynamic(); 来创建一个dynamic对象实例。也许你觉得dynamicvar关键字,可是var关键字只能出现在局部变量的声明中,其实dynamic更像object,和object不同的是dynamic可以支持任何操作,也就是在编写代码的时候你可以一个dynamic类型对象可以调用任何方法而不会产生编译错误,但这并不意味着dynamic可以逃脱类型检测,在运行时后,它还是要被检测,也就是说它的类型以及所执行的操作在运行的时候必须存在,正所谓逃了和尚逃不了庙!有的朋友可能会说DoSomething方法可以使用泛型,我很认真的告诉你在上面的例子中,泛型无能为力,不信你试试?所以基本上你可以把dynamic看成一个占位对象,该占位对象可以绕过编译器的检查。

至于使用dynamic的好处,就要看在什么场合下使用了,好吃的东西也不宜多吃,否则会适得其反的。下面我们通过dynamic的一个兄弟ExpandoObject类来看dynamic在动态编程中的用法:

dynamic user = new ExpandoObject();

user.Name = "user";
user.Password = "p@ssw0rd"; user.Validate = (Func<string,string,bool>)
          (( userid,  password) => userid == "user" && password == "p@ssw0rd" );
user.Validate(user.Name, user.Password);
 
user是ExpandoObject类型的动态对象,类似一个匿名类型,我们在代码中动态定义了两个属性NamePassword,并对它们赋值,然后我们为user对象动态定义了一个Validate方法,最后,我们调用这个定义的方法,读出前面定义的NamePassword的属性值作为方法的参数。

如果你需要的功能ExpandoObject不能满足的话,这时有两个定制方法可以使用,方法1:实现

IDynamicMetaObjectProvider接口;方法2:从DynamicObject类派生
我们先来看看从DynamicObject类中重载来的几个方法的定义(其他方法参见MSDN类库文档)
    public class DynamicObject : IDynamicMetaObjectProvider
    {        
    //提供对获取成员值操作的实现,重载该方法可以实现获取对象属性值操作时行为。
    public virtual bool TryGetMember(GetMemberBinder binder, out object result);
 
    //提供调用成员操作的实现。
  public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result);
    //提供对设置成员值得实现。 
    public virtual bool TrySetMember(SetMemberBinder binder, object value);
     }
 
有了上面dynamic的知识,我们的第一个问题得到了解决。在DynamicAspect中,我们设计了一个名为WeavableObject的类,它从DynamicObject派生,通过对TryInvokeMember方法的重载,我们得到拦截方法调用的机会;而通过对TryGetMemberTrySetMember方法的重载,于是就可以拦截对属性的getset的调用。WeavableObject的部分代码如下所示:
    public sealed class WeavableObject<T> : DynamicObject, 
                         IPartImportsSatisfiedNotification 
                         where T: class
    {
        T source;
        public WeavableObject()
        {
            source = Activator.CreateInstance<T>();
        }         public WeavableObject(T source)
        {
            this.source = source;
        }
     
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {

// 代码暂略

        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
          // 代码暂略
        }         public override bool TrySetMember(SetMemberBinder binder, object value)
        {
          // 代码暂略
        }
 
我们的第二个问题也就解决了。
当我们决定一个对象要被编织的时候,我们就可以在实例化该对象的是时候把它替换成WeavableObject,比如上一篇的Bank对象,我们就可以把代码写成:
 
dynamic bank = new WeavableObject<Bank>();
 WeavableObject的无参数构造器将根据对象的类型通过反射来创建一个对象实例。为了减少反射带来的性能开销,我们也设计了一个带参构造器,所以上面的代码就可以写成:
 
dynamic bank = new WeavalbeObject<Bank>(new Bank());
 
为了使代码看上去更自然,我们编写了一个扩展方法AsDynamic<T>(),于是最终的代码就变成了:
 
dynamic bank = new Bank().AsDynamic();
 
自此,梁柱就这样被换掉了。下一篇将继续探讨其他未解决的问题。
(未完待续)

使用dynamic和MEF实现轻量级的AOP组件 (2)的更多相关文章

  1. 使用dynamic和MEF实现轻量级的AOP组件 ---- 系列文章

      .NET 4 实践 - 使用dynamic 和MEF实现轻量级的AOP组件(1)   .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (2) .NET 4 实践 - 使用 ...

  2. 使用dynamic和MEF实现轻量级的AOP组件 (3)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...

  3. 使用dynamic 和MEF实现轻量级的 AOP 组件 (1)

    转载https://www.cnblogs.com/niceWk/archive/2010/07/19/1780843.html AOP魔法 今天你AOP了吗?谈到AOP,总有一种神秘的感觉,人类对于 ...

  4. .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...

  5. C++11实现一个轻量级的AOP框架

    AOP介绍 AOP(Aspect-Oriented Programming,面向方面编程),可以解决面向对象编程中的一些问题,是OOP的一种有益补充.面向对象编程中的继承是一种从上而下的关系,不适合定 ...

  6. C#轻量级高性能日志组件EasyLogger

    一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第六部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...

  7. 基于DispatchProxy打造自定义AOP组件

    DispatchProxy是微软爸爸编写的一个代理类,基于这个,我扩展了一个AOP组件 暂时不支持依赖注入构造方法,感觉属性注入略显麻烦,暂时没打算支持 基于特性的注入流程 [AttributeUsa ...

  8. 使用MEF与Castle实现AOP

    MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了.现在我们扩展MEF,在其装配生成实例时,使用Castle Dy ...

  9. 基于微软企业库的AOP组件(含源码)

    软件开发,离不开对日志的操作.日志可以帮助我们查找和检测问题,比较传统的日志是在方法执行前或后,手动调用日志代码保存.但自从AOP出现后,我们就可以避免这种繁琐但又必须要实现的方式.本文是在微软企业库 ...

随机推荐

  1. POS-商户手续费-从生活剖析,通俗易懂

    前言 我们大家日常都在使用pos机,尤其是买衣服,吃火锅,都习惯刷卡.pos机带来的消费便利,也正是市场 对经济的一种促进手段. 今天主要分享下商户手续费这个概念,引出这个概念前,我们先大概说点别的东 ...

  2. Mac下安装安装selenium与安装chromedriver安装

    开发环境:MacOS,Python3.7 1. 安装selenium 可以使用pip安装(pip install selenium)或者使用pycharm进行安装下载 2. 运行如下代码: from ...

  3. 读者来信-5 | 如果你家HBase集群Region太多请点进来看看,这个问题你可能会遇到

    前言:<读者来信>是HBase老店开设的一个问答专栏,旨在能为更多的小伙伴解决工作中常遇到的HBase相关的问题.老店会尽力帮大家解决这些问题或帮你发出求救贴,老店希望这会是一个互帮互助的 ...

  4. Unity 游戏框架搭建 2019 (十八~二十) 概率函数 & GameObject 显示、隐藏简化 & 第二章 小结与快速复习

    在笔者刚做项目的时候,遇到了一个需求.第一个项目是一个跑酷游戏,而跑酷游戏是需要一条一条跑道拼接成的.每个跑道的长度是固定的,而怪物的出现位置也是在跑道上固定好的.那么怪物出现的概率决定一部分关卡的难 ...

  5. 空间复杂度(Space Complexity)

    空间复杂度(Space Complexity) 算法得存储量包括: 1.程序本身所占空间. 2.输入数据所占空间. 3.辅助变量所占空间. 输入数据所占空间只取决于问题本身,和算法无关,则只需分析除输 ...

  6. Activiti组任务

    一.Candidate-users候选人 1.需求 在流程定义中在任务节点的assignee固定设置任务负责人,在流程定义时将参数者固定设置在.bpmn文件中,如果临时任务负责人变更则需要修改流程定义 ...

  7. 在 UITextField 中添加删除绑定(绑定删除)

    要解决的问题 在输入框中,需要整体删除诸如 “xxx@xx.com” 或 “@xxxx” 等文本 实现思路 在删除动作时,获取到当前光标的位置,如果在光标正在处在上述文本范围内,就删除一整串文本 如何 ...

  8. 简单实现Win10炫酷下滑关机

    实现效果如下图,鼠标左键按下下拉关机: 先说下实现思路和实现过程(包括失败过程),不想了解的可直接往下拉查看红色字体标注的最终实现方法. 首先实现下滑关机的Windows自带的一个功能(程序)Slid ...

  9. PTA数据结构与算法题目集(中文) 7-41PAT排名汇总 (25 分)

    PTA数据结构与算法题目集(中文)  7-41PAT排名汇总 (25 分) 7-41 PAT排名汇总 (25 分)   计算机程序设计能力考试(Programming Ability Test,简称P ...

  10. MYSQL索引类型。MYSQLc储存引擎

                                                            MYSQL索引类型,MYSQLc储存引擎 MySQL索引创建与删除 MySQL存储引擎的 ...