在写完上篇文章《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接口提供的这些信息实现更复杂的操作。还记得上次说到的拦截器吗?其中一段定义如下:
了解了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。有时间再写些东西上来。