2010-01-28 20 views
6

Un esempio lo spiega meglio:Perché l'intercettatore di DynamicProxy non viene chiamato per * ciascuna * chiamata al metodo virtuale?

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

} 

mi sarei aspettato l'uscita:

Intercepted foo 
foo 
Intercepted bar 
bar 

Invece, ottengo:

Intercepted foo 
foo 
bar 

Perché?

Come funziona il proxy dinamico? Mi aspettavo che il proxy generato a ereditasse dalla classe proxy, tuttavia, sembra che utilizzi la composizione per delegare ciascuno dei metodi nell'interfaccia con proxy all'attuazione effettiva.

Ho provato con il Castello DynamicProxy ed anche con un'implementazione di proxy dinamica più anziani, da Cramon

risposta

9

Sembra che la mia ipotesi fosse giusta.

ho provato lo stesso esempio, solo che questa volta creare il proxy direttamente dal tipo di classe:

Main(){ 

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

} 

Il risultato è stato quello che mi aspettavo, in primo luogo:

Intercepted foo 
foo 
Intercepted bar 
bar 

Questo mi porta alle seguenti conclusioni:

  • durante la creazione di un proxy da un'interfaccia, utilizza composizione ition delegare chiamate all'implementazione
  • quando si crea un proxy da un tipo (classe), esso eredita dal tipo, quindi tutte le chiamate virtuali del tipo di classe chiameranno i metodi sostituiti nel proxy.

Quando si crea un proxy di interfaccia con un'implementazione di interfaccia, il proxy generato sembra qualcosa di simile:

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

Quando si crea un proxy di classe, il codice simile a questo:

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

Sì, questo è più o meno corretto. –

+0

Wow, sei una rockstar nell'universo di Castle DynamicProxy :) Grazie per aver scritto il tutorial! (o dovrei dire, * IL * tutorial;) –

6

Stai utilizzando il metodo CreateInterfaceProxyWithTarget che istruisce il costruttore proxy per creare un proxy per l'interfaccia e inoltrare le chiamate a l'oggetto target, quindi quello che stai vedendo è quello che gli hai chiesto di fare.

Se si desidera che il proxy provenga dalla classe, è necessario utilizzare il metodo CreateClassProxy.

+0

I Ho appena finito di scrivere la mia risposta quando ho visto il tuo :) Quindi sembra che il mio ragionamento fosse giusto. –