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!