First we try, then we trust

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  183 随笔 :: 111 文章 :: 2983 评论 :: 339 引用

在写完上篇文章《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。有时间再写些东西上来。



附录:

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

posted on 2005-01-21 17:13 吕震宇 阅读(2166) 评论(13)  编辑 收藏 所属分类: 其它

评论

#1楼  2005-03-07 16:05 zq [未注册用户]
我觉得这一段不对。是可以实现多个方法的。
◎◎◎◎
不过是有条件的:那就是被合并类只能实现单一方法(多个方法可以通过多个被合并类实现,具体可以参考DynamicProxy的测试用例)。
◎◎◎
  回复  引用    

#2楼 [楼主] 2005-03-08 09:23 吕震宇      
@zq

谢谢指正!其实我并没有去做实验验证是否只能实现单一方法。只是Codeproject上的一句话让我产生了如此的理解,看来英语还是没有过关。“Mixins are a kind of inheritance well-known in the C++ world. In a nutshell, the mixin-style of inheritance is the ability to mix a class with other (or others) which expose a single specific capability. ”内容请见:http://www.codeproject.com/csharp/hamiltondynamicproxy.asp

另外我在DynamicProxy的测试用例中找到了ComplexMixin类实现了多个接口方法。但是它通过层层继承获取的,并且每个接口都只添加了一个接口方法,这就更加深了我的误解。

刚才自己测试了一番,发现接口实现多个方法并没有什么问题。我会尽快修正文中的错误的。谢谢!
  回复  引用  查看    

#3楼  2005-03-08 17:23 zq [未注册用户]
吕先生是一个很认真的人......
.Net下实现动态代理带有那几种方式呢?
spring.net的作者说有三种:
http://opensource.atlassian.com/confluence/spring/display/NET/Dynamic+Proxy

他们也是选择用Emit。

  回复  引用    

#4楼  2005-07-29 13:11 cloud [未注册用户]
我下载不了
能否把原码发给我,谢谢

sg@whty.com.cn
  回复  引用    

#5楼 [楼主] 2005-07-29 16:11 吕震宇      
@cloud

有段时间一直用博客园的www2发文章(速度问题),结果现在遗留下来的问题就是这些文章的链接仍然是www2开头,所以访问不了。现在修改过来了,邮件已经发送,请查收。
  回复  引用  查看    

#6楼  2005-08-02 09:51 cloud [未注册用户]
谢谢,我已经收到。
  回复  引用    

#7楼  2005-08-02 10:13 cloud [未注册用户]
我还有一个问题:
AbstractInvocation 类的成员
AbstractInvocation 类的成员 _proxy在AbstractInvocation 中起什么作用,能否解释一下。他和AbstractInvocation 的属性InvocationTarget有什么区别,我的想法是它们都是动态代理类的实例的引用,不知道是否正确

  回复  引用    

#8楼  2005-08-02 10:16 cloud [未注册用户]
public InvocationTarget
为什么允许它修改,让它可以InvocationTarget != _original_target.不知道有什么含义
  回复  引用    

#9楼 [楼主] 2005-08-02 17:36 吕震宇      
@cloud

由于时间很久,记得不是很清楚了。不过在我印象中似乎为了实现Mixin,_proxy是代理,Target是与之合并的实现某接口的对象,不敢确定,你可以自己读一下代码来印证。
  回复  引用  查看    

#10楼  2005-11-23 17:23 mimi [未注册用户]
如果要对一个类同时有几个拦截方法的话,有方法处理吗

  回复  引用    

#11楼 [楼主] 2005-11-23 19:33 吕震宇      
@mimi

DynamicProxy只是一种实现技术,如果实际应用最好使用AOP实现,那里面提供了你提到的“一个类同时有几个拦截方法”的实现。
  回复  引用  查看    

#12楼  2005-11-24 14:52 mimi [未注册用户]
谢谢,看了你的文章收获很大。
  回复  引用    

#13楼  2008-07-13 22:20 代码乱了      
Mixins功能看上去很迷人,呵呵
  回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-07-29 16:05 编辑过


相关链接: