2010-01-28 10 views
6

Un ejemplo explica mejor:¿Por qué no se llamará el interceptor de DynamicProxy para * cada * llamada al método virtual?

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

} 

lo que habría esperado la salida:

Intercepted foo 
foo 
Intercepted bar 
bar 

En su lugar, me sale:

Intercepted foo 
foo 
bar 

¿Por qué?

¿Cómo funciona el proxy dinámico? Esperaba que el proxy generado fuera herede de la clase proxiada, sin embargo, parece que usa composición para delegar cada uno de los métodos en la interfaz de proxy a la implementación real.

He tratado con el castillo DynamicProxy y también con una aplicación proxy dinámico mayor, de Cramon

Respuesta

9

Parece que mi suposición era correcta.

He probado el mismo ejemplo, sólo que esta vez crear el proxy directamente desde el tipo de clase:

Main(){ 

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

} 

El resultado fue lo que esperaba en primer lugar:

Intercepted foo 
foo 
Intercepted bar 
bar 

Esto me lleva a la siguiente conclusión:

  • al crear un proxy desde una interfaz, usa compos ition para delegar llamadas a la implementación
  • al crear un proxy de un tipo (clase), hereda del tipo, por lo que todas las llamadas virtuales en el tipo de clase llamarán a los métodos reemplazados en el proxy.

Al crear un proxy de interfaz con una implementación de la interfaz, el proxy generada se ve algo como esto:

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

Al crear un proxy de clase, el código es el siguiente:

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í, eso es más o menos correcto. –

+0

Guau, eres una estrella de rock en el universo de Castle DynamicProxy :) ¡Gracias por escribir el tutorial! (o debería decir, * EL * tutorial;) –

6

Estás usando el método CreateInterfaceProxyWithTarget que instruye el constructor proxy para crear un proxy para la interfaz y reenviar las llamadas a el objeto objetivo, entonces lo que está viendo es lo que le pidió que hiciera.

Si desea que el proxy derive de su clase, deberá utilizar el método CreateClassProxy.

+0

I Acabo de escribir mi propia respuesta cuando vi la tuya :) Así que parece que mi razonamiento fue correcto. –

Cuestiones relacionadas