介绍
CLR提供的代理功能非常棒。 不过,这里还是有些缺点,例如:如果要使用代理功能,你的类必须继承自 这篇文章说明了怎么使用Castle Project中的动态代理,使用一个快速、干净的方式为你的类建立一个拦截器(interceptors),如动态代理一样高效,不会使用反射机制去调用一个对象实例的方法。 动态代理能代理接口和实现类,你总是需要提供被代理对象的类型和拦截器的实例,拦截器将会在对代理的每次方法调用的时候被调用,所以你可以在拦截器逻辑中承载一些逻辑(日志、事务等)和然后决定是否继续处理该调用,如果需要继续处理,你必须调用 1 public class MyInterceptor : IInterceptor
2 3 { 4 public object Intercept(IInvocation invocation, params object[] args) 5 { 6 DoSomeWorkBefore(invocation, args); 7 8 object retValue = invocation.Proceed( args ); 9 10 DoSomeWorkAfter(invocation, retValue, args); 11 12 return retValue; 13 } 14 } 15
1 public interface IInvocation
2 { 3 object Proxy { get; } 4 5 object InvocationTarget { get; set; } 6 7 MethodInfo Method { get; } 8 9 object Proceed( params object[] args ); 10 } 11 为了实现接口,你必须标识出目标对象实例,复杂么?其实不然,考虑下面一个例子:
1 public interface IMyInterface
2 { 3 int Calc(int x, int y); 4 int Calc(int x, int y, int z, Single k); 5 } 6 7 public class MyInterfaceImpl : IMyInterface 8 { 9 public virtual int Calc(int x, int y) 10 { 11 return x + y; 12 } 13 14 public virtual int Calc(int x, int y, int z, Single k) 15 { 16 return x + y + z + (int)k; 17 } 18 } 19 20 ProxyGenerator generator = new ProxyGenerator(); 21 22 IMyInterface proxy = (IMyInterface) generator.CreateProxy( 23 typeof(IMyInterface), new StandardInterceptor(), new MyInterfaceImpl() ); 24 这个就是作为DynamicProxy的需求,需要一个针对调用的默认目标 后面我们将解释为什么。 现在,如果你需要代理一个真实类,这个类不能是sealed,而且只有virtual方法才能被拦截,理由是动态代理将为该类建立一个子类,该子类将重载所有方法,所以能把调用放到拦截器中。看下面一个例子:
1 ProxyGenerator generator = new ProxyGenerator();
2 3 Hashtable proxy = (Hashtable) generator.CreateClassProxy( 4 typeof(Hashtable), new HashtableInterceptor() ); 5 6 object value = proxy["key"]; // == "default" 7 8 public class HashtableInterceptor : StandardInterceptor 9 { 10 public override object Intercept(IInvocation invocation, params object[] args) 11 { 12 if (invocation.Method.Name.Equals("get_Item")) 13 { 14 object item = base.Intercept(invocation, args); 15 return (item == null) ? "default" : item; 16 } 17 return base.Intercept(invocation, args); 18 } 19 } 20 如果你不希望代理的类暴露出一个默认的构造函数,OK,你只需要提供一些参数给 MixinsMixins是一种在C++世界很著名的继承,Mixin样式的继承,能将一个类和其他的类进行混合,同时暴露出单独的能力,动态代理允许你一个类和其他的类进行混合,结果将生成一个混合的代理实例,如果混合类暴露接口,他们将自动通过代理实例进行暴露。
1 public interface ISimpleMixin
2 { 3 int DoSomething(); 4 } 5 6 public class SimpleMixin : ISimpleMixin 7 { 8 public int DoSomething() 9 { 10 return 1; 11 } 12 } 13 14 ProxyGenerator generator = new ProxyGenerator(); 15 GeneratorContext context = new GeneratorContext(); 16 17 SimpleMixin mixin_instance = new SimpleMixin(); 18 19 context.AddMixinInstance( mixin_instance ); 20 21 SimpleClass proxy = (SimpleClass) generator.CreateCustomClassProxy( 22 typeof(SimpleClass), interceptor, context ); 23 24 ISimpleMixin mixin = (ISimpleMixin) proxy; 25 象Ruby一样的动态语言是mixins的天堂,每种混合的模块通过目标类暴露,但是那是另一个讨论的主题。
内部实现动态代理生成了一个类,类似如下代码
1 public class ProxyGenerated : YourClass
2 { 3 // Exposes all constructors 4 5 // Overrides all methods 6 7 public override int DoSomething(int x) 8 { 9 MethodInfo m = ldtoken currentMethod; 10 IInvocation invocation = ObtainInvocationFor( deletegateForDoSomething, 11 callableForDoSomething, m); 12 return (int) _interceptor.Intercept( invocation, x ); 13 } 14 15 private int BaseCallDoSomething(int x) 16 { 17 return base.DoSomething(x); 18 } 19 } 20
正如你所见到的,动态代理依靠委托达到很好的性能,唯一的性能瓶井是在对值类型进行装箱和拆箱工作上。 基本上,每个代理都有一个指针指向调用基类方法的另外一个方法,他会在你使用 结论 对于程序集的静态织入,可以考虑RAIL项目,如果你需要的是动态,则考虑动态代理。同时,我也需要谢谢所有的回馈和从Aspect#和Castle开发邮件列表中收到的补丁,动态代理的用户给了我一次又一次重构的力量。 posted on 2005-12-04 |
|