转摘 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. 曹工说Spring Boot源码(28)-- Spring的component-scan机制,让你自己来进行简单实现,怎么办

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  2. iOS MachO

    一.前言 1.1 程序和进程 广义上的程序就是一个静态的可执行文件,是由一个已经编译好的指令和数据集合的一个文件.就像通过 Xcode 编译好的 Mach-O 文件.而进程则是一个动态的概念,是程序的 ...

  3. iOS Hook

    HOOK 译为"钩子"或挂钩.在 iOS 逆向中指改变程序运行流程的一种技术. iOS 中 hook 技术的几种方式 Method Swizzle 利用 OC 的 Runtime ...

  4. Sql Server数据库性能优化之索引

    最近在做SQL Server数据库性能优化,因此复习下一索引.视图.存储过程等知识点.本篇为索引篇,知识整理来源于互联网. 索引加快检索表中数据的方法,它对数据表中一个或者多个列的值进行结构排序,是数 ...

  5. [poj1797]Heavy Transportation<最大生成树prim&kruskal>

    题目链接:http://poj.org/problem?id=1797 题意:给定n个点,m条边,每条边连接两点切有权值.求点1到点n的路径的上的最小边的值最大... 翻别人博客找到的题,方法挺多的, ...

  6. 汇编学习-三(VB)

    闲来无事做了一下160个crackme,因为是VB程序,所以将得到的一点心得记录如下(OD加载注释) push eax ; Andréna.004018A8 call dword ptr ds:[&l ...

  7. Android ConstraintLayout 构建自适应界面

    原文链接 使用 ConstraintLayout 构建自适应界面 ConstraintLayout 可让您使用扁平视图层次结构(无嵌套视图组)创建复杂的大型布局.它与 RelativeLayout 相 ...

  8. 2019NYIST计科第七次周赛总结

    2019NYIST计科第七次周赛总结 文章目录 2019NYIST计科第七次周赛总结 [秤取物体重量( 二进制枚举法)](https://blog.csdn.net/qq_34261446/artic ...

  9. CentOS-7.6 下搭建 NIS 服务器

    ##服务端配置: ####Server: 192.168.0.178(CentOS 7.6) # systemctl stop firewalld # systemctl disable firewa ...

  10. vue按需引入/全局引入echarts

    npm install echarts -S 1.按需引入 新建echarts.js公共引入 // 文件路径 @/lib/echarts.js 自行配置 // 加载echarts,注意引入文件的路径 ...