Caliburn has a powerful yet quite simple extensibility story. I actually rather like it.

Extending Caliburn.Micro

Caliburn.Micro has an interesting extensibility story. Personally, I'd never come across this technique before, and it took a little while for me to grok, but now that I do, I really like it.

To dig into how extensibility works, consider logging: Caliburn has an ILog interface that contains methods Info, Warn and Error as you might expect. Now have a look at the way logging is implemented by default:

First there is a concrete logger that implements ILog. As it happens, it doesn't do anything, but that's neither here nor there - it looks like this

private class NullLog : ILog
{
    public void Info(string format, params object[] args) { }
    public void Warn(string format, params object[] args) { }
    public void Error(Exception exception) { }
}

Now that's not the interesting bit - the interesting bit is how the framework plugs this NullLog in by default - by exposing a static Func as a public field on a LogManager class.

Go and read that back - it's worth it. The LogManager class exposes a field (not a property) called GetLog that is a Func<Type, ILog> - it's a method that takes in a Type as a parameter and returns an ILog for that type, and by default it looks like this:

/// <summary>
/// Creates an <see cref="ILog"/> for the provided type.
/// </summary>
public static Func<Type, ILog> GetLog = type => NullLogInstance;

OK? And to swap out logging for your project? You just need to set the LogManager.GetLog field to be your own method that takes in a Type and returns in ILog for that type.

Maybe if you wanted to create a logger that just writes to the Output window, you'd create something like

class DebugLog : ILog
{
    public void Info(string format, params object[] args)
    {
        System.Diagnostics.Debug.WriteLine(format, args);
    }

    // implement Warn and Error, etc...
}

and then somewhere, probably in the app bootstrapper:

LogManager.GetLog = (type) => new DebugLog();

The deeper you dig into the framework, the more you realise that more and more of the pieces are composed of these static Func methods - which means that whilst Convention over Configuration is working hard for us by default, we have a large amount of power to define those conventions...

Posted by: Ian Randall
Last revised: 11 Aug, 2011 10:59 a.m.

Comments

kiwidev
kiwidev
06 Jul, 2011 09:23 a.m.

I do like this technique of Rob's.

Very similar in many ways to the extensibility model of Javascript (functions being properties of an object and assignable like a variable).

Wonder if dynamics could be used in a very similar manner / simplify this even more?

Your Comments

Used for your gravatar. Not required. Will not be public.
Posting code? Indent it by four spaces to make it look nice. Learn more about Markdown.

Preview