First we try, then we trust

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在写完上篇文章《DynamicProxy(动态代理)技术剖析(1)》后,才发现原来博客园的dudu、hbifts、steeven早在一年前就开始制作AOP.NET了。谢谢hbifts的指导,让我又找到了不少有用的资料。

今天,仍然继续上次话题,把DynamicProxy的Mixins技术和IInvocation接口介绍一下:

上次只说道IInvocation接口中包含了一个回调的Delegate。但IInvocation接口提供的东西要更多,先让我们看看它的定义:

public interface IInvocation
{
  
object Proxy get; }
  
object InvocationTarget get;set; }
  MethodInfo Method 
get; }
  
object Proceed( params object[] args );
}

在这里我们关键讨论一下Proxy属性以及Proceed方法。Proxy提供了对动态生成的DynamicProxy对象的一个引用。而Proceed方法便是对原有方法的"回调"操作。让我们看看在DynamicProxy中提供的一个实现:

namespace Castle.DynamicProxy.Invocation
{
  
using System.Reflection;

  
public abstract class AbstractInvocation : IInvocation
  
{
    
protected ICallable _callable;
    
protected object _original_target;
    
private MethodInfo _method;
    
private object _proxy;
    
private object _target;

    
public AbstractInvocation( ICallable callable, object proxy, MethodInfo method )
    
{
      _callable 
= callable;
      _proxy 
= proxy;
      _target 
= _original_target = callable.Target;
      _method 
= method;
    }


    
public object Proxy
    
get return _proxy; } }

    
public object InvocationTarget
    
{
      
get return _target; }
      
set { _target = value; }
    }


    
public MethodInfo Method
    
get return _method; } }

    
public abstract object Proceed(params object[] args);
  }

  
  
public class SameClassInvocation : AbstractInvocation
  
{
    
public SameClassInvocation(ICallable callable, object proxy, MethodInfo method) : 
      
base(callable, proxy, method)
    
{
    }


    
public override object Proceed(params object[] args)
    
{
      
// If the user changed the target, we use reflection
      
// otherwise the delegate will be used.
      if (InvocationTarget == _original_target)
        
return _callable.Call( args );
      
else
        
return Method.Invoke(InvocationTarget, args);
    }

  }

}

我们可以看到在AbstractInvocation的构造函数中接收一个ICallable类型的参数。我们在上篇文章中提到的代理便实现了ICallable接口(这也是动态生成的代码所实现的)。另外,注意SameClassInvocation类中的Proceed方法,便是调用代理所对应的原有方法。如果用户改变了调用对象的化,也可以通过反射实现同样的功能(看来是双保险)。

了解了这些后,我们可以借助IInvocation接口提供的这些信息实现更复杂的操作。还记得上次说到的拦截器吗?其中一段定义如下:

  public class StandardInterceptor : IInterceptor
  
{
    
public StandardInterceptor(){}
   
protected virtual void PreProceed(IInvocation invocation, params object[] args){}
       ……

PreProceed与PostProceed都接收一个IInvocation类型的对象,我们可以使用invocation.Proxy获取对DynamicProxy对象的一个引用,然后通过强制类型转换转换成希望的类型,再进行一些具体操作……,就不用我细说了吧。

了解了IInvocation后,我们再来看看DynamicProxy提供的Mixins功能。Mixins允许我们将某个合并类和另外一个被合并类"合并"起来,并以此来为被合并类添加新的功能。除此之外,为了确保能够调用到合并后的类的具体方法,最好将让被合并类实现某个接口,这样就可以通过类型转换达到调用目的。还是看一段代码吧:

public interface ISimpleMixin
{
  
void DoSomethingInMixin();
}


[Serializable]
public class SimpleMixin : ISimpleMixin
{
  
public SimpleMixin()
  
{
  }


  
public void DoSomethingInMixin()
  
{
    Console.WriteLine(
"This is in Mixin Method.");
  }

}


public class MainClient
{
  
public static void Main()
  
{
    ProxyGenerator _generator 
= new ProxyGenerator();
    GeneratorContext context 
= new GeneratorContext();
    SimpleMixin mixin_instance 
= new SimpleMixin();
    context.AddMixinInstance( mixin_instance );

    TimeUsedInterceptor interceptor 
= new TimeUsedInterceptor();

    
object proxy = _generator.CreateCustomClassProxy( typeof(SimpleClass), interceptor, context );
    
    ((SimpleClass) proxy).DoSomething();
    ((ISimpleMixin) proxy).DoSomethingInMixin();

    Console.ReadLine();
  }

}

SimpleMixin类实现了ISimpleMixin接口,该接口只有一个方法DoSomethingInMixin。在主程序中,我们可以将Mixins添加到GeneratorContext对象后提供给ProxyGenerator对象进行"合并"生成,于是产生出来的proxy对象就既有SimpleClass提供的方法,又有SimpleMixin提供的方法。我们可以将proxy对象分别转换成对应的SimpleClass类型与ISimpleMixin类型来调用其中的方法。

在研究学习时发现,尽管合并后就成为一个对象了,但SimpleClass与Mixin之间无法互相访问受保护成员与私有成员。因为"合并"是动态生成的,在合并前,两者无法相互访问私有成员,这在编译上是通不过的。但是相互间却可以访问公有成员。这要稍微麻烦一些,我们可以通过改进设计来实现,最终代码可能会象这样:

((ISimpleMixin) proxy).DoSomethingInMixin((SimpleClass) proxy);

于是ISimpleMixin便访问到了SimpleClass成员,其实都是一回事,都是proxy。

关于DynamicProxy的技术剖析到这里就结束了。本人下一步决定学习一下AOP。有时间再写些东西上来。



附录:

本篇文章的完整代码下载: https://files.cnblogs.com/zhenyulu/Mixins.rar

posted on 2005-01-21 17:13  吕震宇  阅读(3611)  评论(13编辑  收藏  举报