Perché non DynamicProxy dell'interceptor chiamato per *ogni* metodo virtuale chiamata?
-
23-09-2019 - |
Domanda
Un esempio spiega meglio :
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 dynamic proxy lavoro?Mi aspettavo il proxy generato per ereditare da proxy di classe, tuttavia, sembra che la utilizza composizione di delegare ciascuno dei metodi approssimati di interfaccia per l'effettiva attuazione.
Ho provato con il Castello DynamicProxy e anche con una vecchia dynamic proxy attuazione, da Cramon
Soluzione
Sembra la mia ipotesi era giusta.
Ho provato lo stesso esempio, solo che questa volta la creazione di 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 alla seguente conclusione:
- durante la creazione di un proxy da un'interfaccia, utilizza composizione per delegare le chiamate per l'attuazione
- durante la creazione di un proxy da un (classe) tipo di eredita il tipo, in modo virtuale chiama il tipo di classe provvederà a chiamare i metodi ridefiniti nel proxy.
Durante la creazione di un proxy di interfaccia con un'implementazione dell'interfaccia, proxy generata sembra qualcosa di simile a questo:
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();
}
}
Durante la creazione di una classe proxy, 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();
}
}
Altri suggerimenti
Si sta utilizzando il metodo CreateInterfaceProxyWithTarget
che istruisce il costruttore proxy per creare un proxy per l'interfaccia e inoltrare le chiamate verso l'oggetto di destinazione, in modo da quello che stai vedendo è quello che hai chiesto di fare.
Se si desidera che il proxy per derivare dalla classe allora avresti bisogno di utilizzare il metodo CreateClassProxy
invece.