2010-01-28 97 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

相關問題