Пример объясняет это лучше всего:
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
Похоже, моя догадка была верна.
Я попробовал тот же пример, только на этот раз создавая прокси непосредственно из типа класса:
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
Это приводит меня к следующему выводу:
При создании интерфейсного прокси с реализацией интерфейса, созданный прокси выглядит примерно так:
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();
}
}
Вы используете метод CreateInterFaceProxyWithTarget
, который поручает Proxy Builder создать прокси для интерфейса и пересылать вызовы на целевой объект, так что вы видите это то, что вы просили это сделать.
Если вы хотите, чтобы прокси получил от вашего класса, то вместо этого вам нужно будет использовать метод CreateClassProxy
.