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!