Castle Dynamic Proxy FAQ: why there’s no “class proxy with target”

One of the commonly asked questions about Castle Dynamic Proxy:

How do I use CreateClassProxy to wrap an existing object to intercept calls to its virtual members?

Short answer is – you can’t. And if you think about it, there’s a very good reason for that.

Since classes are stateful, and there’s no requirement that all their members are virtual, you could end up with inconsistent state, where part of the state comes from proxy object, part comes from the target object. This would lead to bizarre behavior and bugs, that would be hard to catch. For that reason Dynamic Proxy does not expose this functionality.
You can either expose the required set of API as interface and create interface proxy with target interface, or to create a wrapper class.

Example

If that’s not clear enough, consider the following example of how such proxy could look like and behave:

class Program

{

    static void Main(string[] args)

    {

        var joe = new PersonImpl(17);

 

        Debug.Assert( joe.IsAdult() == false );

        var proxy = new PersonProxyWithTarget( joe );

        Debug.Assert(proxy.IsAdult() == false);

        proxy.HasBirthday();

        Debug.Assert(joe.IsAdult() != proxy.IsAdult()); // <- we have an issue here

    }

}

 

public abstract class Person

{

    protected int age;

 

    public abstract int HasBirthday();

 

    public bool IsAdult()

    {

        return this.age >= 18;

    }

}

 

public class PersonProxyWithTarget : Person

{

    private readonly Person target;

 

    public PersonProxyWithTarget(Person target)

    {

        this.target = target;

    }

 

    public override int HasBirthday()

    {

        CallInterceptors();

        return target.HasBirthday();

 

    }

 

    private void CallInterceptors()

    {

        //calls interceptors

    }

}

 

public class PersonImpl : Person

{

    public PersonImpl( int age )

    {

        this.age = age;

    }

 

    public override int HasBirthday()

    {

        return this.age++;

    }

}

As you can see here, we have a class which has some state in it. We then create a proxy, and call some methods. The important thing is the last assert. Proxy returns invalid results to us – we have a bug! While the proxy should be transparent, and behave as if it was the joe himself, it returns false values to us. This is not something that can be worked around, hence no class proxies with targets.

  • Geoff McElhanon

    Why not give us the scissors with a warning label and let us decide if we want to run with them? I believe I have a legitimate reason for wanting this functionality, and I know I’m not going to get into trouble with it in my scenario.

    It would be great to be able to dynamically slap on a wrapper class in a testing scenario with the opportunity to monitor the calls being made to a class for completeness.

  • @Geoff

    Perhaps we will. There’s a suggestion for this on UserVoice site, and one person actually started playing with implementing it.
    castle.uservoice.com/…/509003-allow-proxying-…