Почему перехватчик DynamicProxy не будет требоваться *каждый* виртуальный вызов метода?

Пример объясняет это лучше всего:

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

11
задан abatishchev 12 August 2019 в 04:33
поделиться

2 ответа

Похоже, моя догадка была верна.

Я попробовал тот же пример, только на этот раз создавая прокси непосредственно из типа класса:

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();
  }
}
14
ответ дан 3 December 2019 в 05:12
поделиться

Вы используете метод CreateInterFaceProxyWithTarget , который поручает Proxy Builder создать прокси для интерфейса и пересылать вызовы на целевой объект, так что вы видите это то, что вы просили это сделать.

Если вы хотите, чтобы прокси получил от вашего класса, то вместо этого вам нужно будет использовать метод CreateClassProxy .

8
ответ дан 3 December 2019 в 05:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: