12

例はそれを最もよく説明します:

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

なんで?

動的プロキシはどのように機能しますか?生成されたプロキシがプロキシされたクラスから継承することを期待していましたが、 compositionを使用して、プロキシされたインターフェイスの各メソッドを実際の実装に委任しているようです。

Castle DynamicProxyと、Cramonの古い動的プロキシ実装を試してみました

4

2 に答える 2

14

私の推測は正しかったようです。

同じ例を試しましたが、今回はクラスタイプから直接プロキシを作成しました。

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();
  }
}
于 2010-01-28T09:39:10.707 に答える
8

インターフェイスのプロキシを作成し、呼び出しをターゲットオブジェクトに転送するようにプロキシビルダーに指示するメソッドCreateInterfaceProxyWithTargetを使用しているため、表示されているのは、要求した内容です。

プロキシをクラスから派生させたい場合は、CreateClassProxy代わりにメソッドを使用する必要があります。

于 2010-01-28T09:00:56.457 に答える