2010-01-28 1 views
6

Ein Beispiel erklärt es am besten:Warum wird der Interceptor von DynamicProxy nicht für jeden * virtuellen Methodenaufruf aufgerufen?

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(); 

} 

Ich würde den Ausgang zu erwarten:

Intercepted foo 
foo 
Intercepted bar 
bar 

Stattdessen erhalte ich:

Intercepted foo 
foo 
bar 

Warum?

Wie funktioniert der dynamische Proxy? Ich habe erwartet, dass der generierte Proxy von der proxied-Klasse erbt, jedoch scheint es, dass es Zusammensetzung verwendet, um jede der Methoden in der Proxy-Schnittstelle an die tatsächliche Implementierung zu delegieren.

Ich habe versucht, mit Schloss und Dynamic auch mit einer älteren dynamischen Proxy-Implementierung von Cramon

Antwort

9

Sieht aus wie meine Vermutung war richtig.

habe ich versucht, das gleiche Beispiel, nur dieses Mal den Proxy direkt aus dem Klassentyp zu erstellen:

war
Main(){ 

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

} 

Das Ergebnis, was ich in erster Linie erwartet:

Intercepted foo 
foo 
Intercepted bar 
bar 

Dies führt mich zu der folgenden Schlussfolgerung:

  • Beim Erstellen eines Proxy von einer Schnittstelle verwendet es Compos ition zum Delegieren von Aufrufen an die Implementierung
  • beim Erstellen eines Proxys von einem (Klasse) -Typ erbt vom Typ, so dass alle virtuellen Aufrufe im Klassen-Typ die überschriebenen Methoden im Proxy aufrufen.

Wenn eine Schnittstelle Proxy mit einer Interface-Implementierung zu schaffen, sieht die generierte Proxy etwas wie folgt aus:

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(); 
    } 
} 

Wenn eine Klasse Proxy erstellen, sieht der Code wie folgt aus:

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

Ja, das ist mehr oder weniger korrekt. –

+0

Wow, du bist ein Rockstar im Castle DynamicProxy Universum :) Danke für das Schreiben des Tutorials! (oder sollte ich sagen, * DAS * Tutorial;) –

6

Sie verwenden die Methode CreateInterfaceProxyWithTarget, die den Proxy-Builder weist einen Proxy für die Schnittstelle zu erstellen und leiten die Anrufe das Zielobjekt, also was Sie sehen, ist, was Sie gefragt haben, es zu tun. Wenn Sie möchten, dass der Proxy von Ihrer Klasse abgeleitet wird, müssen Sie stattdessen die Methode verwenden.

+0

I gerade fertig, meine eigene Antwort zu schreiben, als ich deine sah :) So sieht es aus, dass meine Argumentation richtig war. –

Verwandte Themen