hBifTs

山自高兮水自深!當塵霧消散,唯事實留傳.荣辱不惊, 看庭前花开花落; 去留随意, 望天上云展云舒.

导航

Interposer - 实现AOP的又一个方法...

Posted on 2004-03-31 21:49  hbiftsaa  阅读(4552)  评论(14编辑  收藏  举报

Zezeze...怎么每次新的技术,好的思想都是外国人发现/发明的呢??难道中国人就想不到么?还是别的什么了........

在上一篇文章中,我介绍了使用DynamicProxy实现ExceptionLog的方法..其核心思想就是通过Reflection得到实际对象的接口类(其实得到的是接口的函数描述),从得到的接口类动态派生一个类,这个类的所有函数(从接口继承下来的)都被Hook了.此对象的所有函数调用都转向Invoke....

今天我来介绍一个比较简单的方法...其实这个东东在Steeven的帖子利用Attribute给C#实现AOP? 的评论就提到过的:P
我们一步一步的看这个东东的代码:P
   public class Interposer      :
      System.Runtime.Remoting.Proxies.RealProxy,
      System.Runtime.Remoting.IRemotingTypeInfo

好,上面的是类的声明,可以看出来,这个类是继承自RealProxy..呵呵,有没有想到什么?  对使用透明代理..是的....那实际的类得从MarshalByRefObject 继承么??还有,那个IRemotingTypeInfo是干什么的?? 呵呵,不用急,..我们再看后面的...

      private Interposer( object target )
         :
         base( typeof( IInterposed ) )
      {
         m_target = target;
      }
可以看出来,传给基类的参数是一个IInterposed的类型..
   public interface IInterposed
   {
      object Target
      {
         get;
      }
   }
这是一个接口,没有任何方法,也没有实现任何属性.Zeze,又是问号??.不急,我们慢慢看后面的..

      public override System.Runtime.Remoting.Messaging.IMessage Invoke( System.Runtime.Remoting.Messaging.IMessage message )
      {
         System.Runtime.Remoting.Messaging.IMethodCallMessage methodMessage =
            new System.Runtime.Remoting.Messaging.MethodCallMessageWrapper( (System.Runtime.Remoting.Messaging.IMethodCallMessage) message );

         System.Reflection.MethodBase method = methodMessage.MethodBase;

         object returnValue = null;

         // Handle IInterposed methods/properties here.  Right now, there is
         // only one property, so don't do any extensive checking to determine
         // the method being invoked.
         if ( method.DeclaringType == typeof( IInterposed ) )
         {
            returnValue = m_target;
         }
         else
         {
    try {
     returnValue = method.Invoke( m_target, methodMessage.Args );
    }
    catch (System.Exception ex) {
    returnValue = null;
    }
         }

         System.Runtime.Remoting.Messaging.ReturnMessage returnMessage =
            new System.Runtime.Remoting.Messaging.ReturnMessage( returnValue, methodMessage.Args, methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage );

         return returnMessage;
      }
既然是通过透明代理实现的,那就得有Invoke函数,对,上面就是这个函数.
通过上面的代码,我们可以发现,实际上是调用对象m_target的函数,m_target就是构造函数中传进去的对象...
这就是生成透明代理的地方了:
      public static object Wrap( object target )
      {
         Interposer interposer = new Interposer( target );
         return interposer.GetTransparentProxy();
      }

呵呵,到这里应该大部分都明白了,通过构造函数把实际的对象(你想操作的)传进去,得到透明代理,再通过透明代理进行调用..

咦,等等,传给RealProxy类的参数是IInterposed啊,不是我们实际的对象啊????

嗯,这就是"the key".因为我们这个类继承自IRemotingTypeInfo,实现这个接口后,我们可以把这个类型转化为任何类型(理论上,而且只是在编译时可以通过编译.如果在程序运行时把这个转成别的完全不一样的类,那会在调用函数时产生异常的).那么在调用强行转换后的类的函数时,通过透明代理,会把此对象的所有的函数调用信息(就算他自己没有这个函数,也会转发的,不会产生异常,如果没用透明代理,那就会像前面说的那样,产生异常)转发给Invoke函数,在这里,我们就调用实际的函数了.酱紫,我们就完成了函数调用的乾坤大挪移了:P...

好了,核心部分说完了.再看看Client调用方式:
   public interface ISampleTarget
   {
      void DoSomething();
      void DoException();
   }

   public interface INotImplemented
   {
      void Nothing();
   }

   public class SampleTarget : ISampleTarget,INotImplemented
   {
      public void DoSomething()
      {
         System.Console.WriteLine( "Doing Something." );
      }

      public void DoException( out int value )
      {
              throw new System.Exception("tt"); //测试异常
     }

   }
同样的,我们得从接口继承类...
         SampleTarget realTarget = new SampleTarget();

         ISampleTarget interposedTarget = (ISampleTarget) Interposer.Interposer.Wrap( realTarget );

         interposedTarget.DoSomething();

         object target = ( (Interposer.IInterposed) interposedTarget ).Target;

         System.Console.WriteLine( "Interposed target type: {0}", target.GetType() );

         INotImplemented target2 = (INotImplemented) interposedTarget;

         try
         {
            target2.Nothing();
         }
         catch ( System.Exception e )
         {
            System.Console.WriteLine( "Expected exception: {0}", e );
         }

从代码中红色的部分可以看出来,把
Interposer对象转换成ISampleTarget(还记得我前面说得吗?? :) ),再调用函数....
呵呵,运行一下效果就完全出来了...

源文件从这个地方下载: Interposer

上述这个方法很轻便,比使用Emit的方式要简单的多...但是和DynamicProxy一样,还是不能Interrupt 构造函数...
看来我们可能还得等JGTM的大作了:P