Castle Dynamic Proxy tutorial part VII: Kinds of proxy objects

This is part seven of my tutorial on Castle Dynamic Proxy.

So far all we have been doing with our simple freezable library is creating a proxies for classes. Not only that, we also introduced one artificial limitation – proxied classes had to have default, parameterless constructor. You can see it by writing the following test:

[Fact]
public void Freezable_should_be_able_to_call_nonDefault_constructor()
{
    var dog = Freezable.MakeFreezable<Dog>("Rex");
    Assert.Equal("Rex", dog.Name);
}
 
public class Dog
{
    public Dog(string name)
    {
        Name = name;
    }
 
    public virtual string Name { get; set; }
}

This test however will not compile.

dptutorial_7_no_default_constructor_error

If we tried to proxy a class with no such constructor, we would get a compilation error.

The compile time error would be a result of the new() generic type constraint we put in MakeFreezable method. It is important to understand that it has nothing to do with Castle Dynamic Proxy. If we removed the constraint we would be able to compile the code, and then get the exception from Dynamic Proxy at runtime: “System.MissingMethodException : Constructor on type ‘DogProxyc319d54e871741668ed468410d1b1013’ not found”.

There is however an overload of CreateClassProxy method that allows you to pass parameters to proxied type constructor. All we need to do, is to refactor the MakeFreezable method.

public static TFreezable MakeFreezable<TFreezable>(params object[] ctorArguments) where TFreezable : class
{
    var freezableInterceptor = new FreezableInterceptor();
    var options = new ProxyGenerationOptions(new FreezableProxyGenerationHook()) { Selector = _selector };
    var proxy = _generator.CreateClassProxy(typeof(TFreezable), new Type[0], options, ctorArguments,
                                            new CallLoggingInterceptor(), freezableInterceptor);
    return proxy as TFreezable;
}

We remove the new() constraint, since it obviously is not needed. We also add an array parameter to the method that we can use to pass arguments to the proxied type constructor. We can use params C# keyword to make the calling of the method a little bit more convenient.

Note that, since we’re passing the arguments as untyped array of objects, you can still get a runtime error if you pass incorrect arguments. This solution is also not refactoring friendly, so If you refactor your constructor and for example reorder its parameters, the parameters passed to MakeFreezable will not be reordered. You might want to change this by using lambda expressions as I described here a while ago. With that you get refactoring support and strong typing.

Other than class proxies, Proxy generator class is able to create three different kinds of interface proxies:

dptutorial_7_proxy_kinds

  • Proxy with target. This one is very easy to explain. We want to proxy an interface. Since interface can’t exist on its own, we need a class that implements it. The instance of this class is the target. It’s very similar to the class proxy we’ve been talking about.
  • Proxy without target. This one is tricky. You don’t supply target implementation for the interface. Dynamic Proxy generates it for you at runtime, using interceptors to provide behavior for its methods.
  • Proxy with target interface. This one is quite similar to proxy with target. You do have to provide a target implementation for the interface. The difference is, you can swap it later, and make the method be called on some other object.

We will cover each kind of interface proxy in forthcoming parts of the tutorial, so that hopefully this will all become crystal clear.

If you have any suggestions or questions, feel free to leave a comment.

Technorati Tags: ,