“Faux” Multiple Inheritance with Extension Methods

Here was my scenario: I had a project with a bunch of classes that used a common logger. I wanted each of the classes to “tag” logged messages with their type to improve traceability. I created a simple wrapper for my logging methods, like so:

public class Animal
{
    public ILogger Logger { get; set; }

    private void Foo()
    {
        // logs "[Animal] Called from Foo!"
        LogInformation("Called from Foo!");
    }

    private void LogError(string message, params object[] args)
    {
        Log(x => x.LogError(message, args));
    }

    private void LogInformation(string message, params object[] args)
    {
        Log(x => x.LogInformation(message, args));
    }

    private void Log(Action<string> logAction, string message, params object[] args)
    {
        if (Logger == null)
        {
            return;
        }
        var msg = string.Format("[{0}] {1}",
                this.GetType().Name,
                string.Format(message, args));
        logAction(msg);
    }
}

When I log messages from this class, they look like “[Animal] some message,” and I can easily see where they came from. Great, but I wanted this functionality in a few more places and I didn’t want to copy/paste the same code into each class that needed it. (DRY, you know?)

So, instead, I created a new interface and created some extension methods for it.

public interface ILogging
{
    ILogger Logger { get; }
}

public static class LoggingExtensions
{
    public static void LogError(this ILogging instance, string message, params object[] args)
    {
        Log(instance, x => instance.Logger.LogError(x), message, args);
    }
    
    public static void LogInformation(this ILogging instance, string message, params object[] args)
    {
        Log(instance, x => instance.Logger.LogInformation(x), message, args);
    }
    
    private static void Log(this ILogging instance, Action<string> logAction, string message, params object[] args)
    {
        if (instance.Logger == null)
        {
            return;
        }
        var msg = string.Format("[{0}] {1}",
                instance.GetType().Name,
                string.Format(message, args));
        logAction(msg);
    }
}

This isn’t quite as pretty as the original, but it’s a snap to re-use. Here’s a look at the example from above, refactored to implement the new interface and use its extension methods:

public class Animal : ILogging
{
    public ILogger Logger { get; set; }

    private void Foo()
    {
        // logs "[Animal] Called from Foo!"
        this.LogInformation("Called from Foo!");
    }
}

What’s really neat about this is that I get “inheritance behavior” without having to actually derive from a base class. This is valuable since you can only inherit from a single class in C#. You are allowed to implement many interfaces, though, so this technique gives you a “faux multiple inheritance” behavior without inheriting from any classes. Cool!

Advertisement

Author: Adam Prescott

I'm enthusiastic and passionate about creating intuitive, great-looking software. I strive to find the simplest solutions to complex problems, and I embrace agile principles and test-driven development.

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: