2010-01-28 93 views
6

一个例子最能解释它:为什么DynamicProxy的拦截器不会为每个虚拟方法调用调用?

public interface IA { 
    void foo(); 
    void bar(); 
} 

public class A : IA { 
    public virtual void foo(){ 
    Console.Write("foo"); 
    bar();     //call virtual method 
    } 
    public virtual void bar(){ 
    Console.Write("bar"); 
    } 
} 

public class Interceptor : IInterceptor { 
    public void Intercept(IInvocation invocation) 
    { 
    Console.WriteLine("Intercepted: " + invocation.Method.Name); 
    invocation.Proceed(); 
    } 
} 

Main(){ 
    IA a = new A(); 

     //proxy-ing an interface, given an implementation 
    IA proxy = new Castle.DynamicProxy.ProxyGenerator() 
       .CreateInterfaceProxyWithTarget(a, new Interceptor()); 
    proxy.foo(); 

} 

我本来期望输出:

Intercepted foo 
foo 
Intercepted bar 
bar 

相反,我得到:

Intercepted foo 
foo 
bar 

为什么?

动态代理如何工作? 我期待生成的代理从代理类继承,但是,它似乎使用组合将代理接口中的每个方法委托给实际实现。

我试着城堡DynamicProxy,并与旧的动态代理实现,从Cramon

回答

9

看起来我的猜测是正确的。

我尝试相同的例子,只是这一次直接从类类型创建代理:

Main(){ 

    //proxy-ing an explicit type 
    A proxy = (A) new Castle.DynamicProxy.ProxyGenerator() 
       .CreateClassProxy<A>(new Interceptor()); 
    proxy.foo(); 

} 

的结果是什么,我期待在首位:

Intercepted foo 
foo 
Intercepted bar 
bar 

这使我得出如下结论:

  • 从接口创建代理时,它使用组合ition将代理呼叫委托给实施
  • 从(类)类型创建代理时,从该类型继承,因此类类型中的所有虚拟调用都将调用代理中的重写方法。

当创建一个接口实现的接口代理,生成的代理看起来是这样的:

class InterfaceProxy: IA { //implements interface 
    IA m_impl; 
    [...] 

    Proxy(IA i_impl){ 
    m_impl = i_impl; 
    } 
    public void foo(){ 
    //overly-simplified, but you get the picture 
    InvokeInterceptors("foo"); 

    //execution gets here when calling 'invocation.Proceed()' 
    //from the interceptor 

    m_impl.foo(); //pass the execution to the implementation; 
        //the proxy has no more control over what gets executed. 

    } 
    public void bar(){ 
    InvokeInterceptors("bar"); 
    m_impl.bar(); 
    } 
} 

当创建一个类代理,代码如下所示:

class ClassProxy: A { //inherits class type 

    Proxy(): base() { ... } 

    public override void foo(){ 
    InvokeInterceptors("foo"); 

    //execution gets here when calling 'invocation.Proceed()' 
    //from the interceptor 

    base.foo(); //pass the execution to the base class 

    } 
    public void bar(){ 
    InvokeInterceptors("bar"); 
    base.bar(); 
    } 
} 
+0

是的,这或多或少是正确的。 – 2010-01-28 10:58:57

+0

哇,你是Castle DynamicProxy宇宙中的摇滚明星:) 感谢您编写教程! (或者我应该说,*教程;) – 2010-01-28 15:14:05

6

您正在使用的指示代理建设者方法CreateInterfaceProxyWithTarget来为接口的代理,并转发给呼叫目标对象,所以你看到的是你要求它做的。

如果您希望代理派生自您的课程,那么您需要使用CreateClassProxy方法。

+0

我当我看到你的时候,刚写完自己的答案:)所以看起来我的推理是正确的。 – 2010-01-28 09:40:40

相关问题