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