Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't DynamicProxy's interceptor get called for *each* virtual method call?

An example explains it best :

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

}

I would have expected the output:

Intercepted foo
foo
Intercepted bar
bar

Instead, I get:

Intercepted foo
foo
bar

Why?

How does the dynamic proxy work? I was expecting the generated proxy to inherit from the proxied class, however, it seems that it uses composition to delegate each of the methods in the proxied interface to the actual implementation.

I've tried with Castle DynamicProxy and also with an older dynamic proxy implementation, from Cramon

like image 796
Cristian Diaconescu Avatar asked Jan 28 '10 07:01

Cristian Diaconescu


1 Answers

Looks like my guess was right.

I tried the same example, only this time creating the proxy directly from the class type:

Main(){

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

}

The result was what I expected in the first place:

Intercepted foo
foo
Intercepted bar
bar

This leads me to the following conclusion:

  • when creating a proxy from an interface, it uses composition to delegate calls to the implementation
  • when creating a proxy from a (class) type, it inherits from the type, so all virtual calls in the class type will call the overridden methods in the proxy.

When creating an interface proxy with an interface implementation, the generated proxy looks something like this:

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

When creating a class proxy, the code looks like this:

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();
  }
}
like image 68
Cristian Diaconescu Avatar answered Oct 30 '22 19:10

Cristian Diaconescu