Lazy Loaded Interceptors

Patterns of Enterprise Application Architecture defines Lazy Load as:

An object that doesn’t contain all of the data you need but knows how to get it.

 

A while back I was trying to figure out how to lazy load objects from a container, so that I didn’t need to depend on the objects dependencies needing to be wired up in the correct order. The syntax I was looking for was something like the following….

 
container.AddProxyOf(
    new ReportPresenterTaskConfiguration(),
    new ReportPresenterTask(
        Lazy.Load<IReportDocumentBuilder>(),
        Lazy.Load<IApplicationSettings>())
    );

Lazy.Load<T> will return a proxy in place of an actual implementation. This is just a temporary place holder that will forward the calls to the actual implementation. It wont load an instance of the actual type until the first time a call is made to it.

public class when_calling_a_method_with_no_arguments_on_a_lazy_loaded_proxy : lazy_loaded_object_context
{
    [Observation]
    public void should_forward_the_original_call_to_the_target()
    {
        target.should_have_been_asked_to(t => t.OneMethod());
    }

    protected override void establish_context()
    {
        target = dependency<ITargetObject>();

        test_container
            .setup_result_for(t => t.find_an_implementation_of<ITargetObject>())
            .will_return(target)
            .Repeat.Once();
    }

    protected override void because_of()
    {
        var result = Lazy.Load<ITargetObject>();
        result.OneMethod();
    }

    private ITargetObject target;
}

So when the method “OneMethod” is called on the proxy. It should forward the call to the target, which can be loaded from the container. The implementation depends on Castle DynamicProxy, and looks like the following…

public static class Lazy
{
    public static T Load<T>() where T : class
    {
        return create_proxy_for<T>(create_interceptor_for<T>());
    }

    private static LazyLoadedInterceptor<T> create_interceptor_for<T>() where T : class
    {
        Func<T> get_the_implementation = resolve.dependency_for<T>;
        return new LazyLoadedInterceptor<T>(get_the_implementation.memorize());
    }

    private static T create_proxy_for<T>(IInterceptor interceptor)
    {
        return new ProxyGenerator().CreateInterfaceProxyWithoutTarget<T>(interceptor);
    }
}

internal class LazyLoadedInterceptor<T> : IInterceptor
{
    private readonly Func<T> get_the_implementation;

    public LazyLoadedInterceptor(Func<T> get_the_implementation)
    {
        this.get_the_implementation = get_the_implementation;
    }

    public void Intercept(IInvocation invocation)
    {
        var method = invocation.GetConcreteMethodInvocationTarget();
        invocation.ReturnValue = method.Invoke(get_the_implementation(), invocation.Arguments);
    }
}

public static class func_extensions
{
    public static Func<T> memorize<T>(this Func<T> item) where T : class
    {
        T the_implementation = null;
        return () => {
                   if (null == the_implementation) {
                       the_implementation = item();
                   }
                   return the_implementation;
               };
    }
}

“resolve” is a static gateway to the underlying IDependencyRegistry. This idea was totally inspired by JP’s strongly typed selective proxies. If you haven’t already, you should definitely check it out.

Download the source.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Mo Khan

mO, is just a kid who's excited about writing software. He's a student of his profession, and just wants to share his thoughts on software development.
This entry was posted in Books, Design Patterns, TDD, Tools. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to Lazy Loaded Interceptors

  1. chadmyers says:

    Interesting. It’s good to see more stuff around DynamicProxy. It’s quite powerful, but I think people are afraid to use it because it can be intimidating to use at first.

    Small side note: For some reason, whatever mechanism you’re using to post code looks really messed up in the RSS feed. It looks fine on the site, though.

    One last thing: Are you building your own IoC container? Interesting! Is it open source where we can see/play with it?

    Thanks!

  2. Mo says:

    @Chad I’m just using Castle Windsor. We just build an abstraction over it, to be able to configure it how we like.

    Thanks for the kind feedback! I’ve been using the “Paste from Visual Studio” plugin for Windows Live Writer. I’d be happy to try a different plugin if you can suggest one!

  3. Jonathan says:

    There is another IoC container that’s worth looking into in your situation. It’s called Autofac – it actually solves a number of the problems you’ve brought up. Specifically you don’t have to register things in a certain order. It also supports better wire-ups through code (delegate/lambda registrations) than Castle Windsor. We switched a while back from Castle Windsor to Autofac and have never looked back.

    On a related note, Microsoft actually grabbed the author of both Castle and Autofac to work on the same project together because they both demonstrated amazing understanding and design prowess in creating their respective IoC containers.

  4. Mo Khan says:

    @Jonathan I’m looking at Autofac right now… I can already understand why they claim to be “An addictive .NET IoC container.” Thanks for introducing me to it!