In my last post I shown you how to build a simple logging framework for Silverlight applications and use it with an IoC container through ‘constructor injection’, well…in my opinion I consider that a bad programming practice. In short when using a Dependency Injection library you have two types of DI mechanism:

  • Constructor Injection: DI through constructor parameters, the DI container try us the constructor that matches best all the modules it knows.
  • Property Injection: DI through properties, the DI container try to resolve each property based on the modules it knows.

Usually I use constructor injection for all the modules I consider mandatory and property injection for optional modules. A logging system does not add nor carry any ‘core level’ feature to the application, it’s merely accessorial (even if extremely useful); so a good practice is to not use constructor injection to initialize it, use property injection instead.

Consider something like this:

public class TestLoggingClass
{
 public TestLoggingClass()
 { }

 public ILogger Logger { get; set; }

 public void Operation()
 {
    Logger.Info("Operation started");
    Logger.Debug("Operation started");
 }
}

In this scenario we cannot call something like: Logger.Info()…because Logger can be null (remember it’s optional now);

We have two diffirent solution to this problem:

  • Register a default NullLogger instance that actually does nothing.
  • Another simple solution is the to write down some extension methods that checks for Logger nullability before actually making the call, each method will be just a wrapper around your framework call:
public static class LoggingExtensions
{
  #region Debug

  public static void SafeDebug(this ILogger logger, string message)
  {
     if (logger != null)
        logger.Debug(message);
  }

  public static void SafeDebug(this ILogger logger, string message, Exception exception)
  {
     if (logger != null)
        logger.Debug(message, exception);
  }

  public static void SafeDebug(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.Debug(format, args);
  }

  public static void SafeDebugFormat(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.DebugFormat(format, args);
  }

  public static void SafeDebugFormat(this ILogger logger, Exception exception, string format, params object[] args)
  {
     if (logger != null)
        logger.DebugFormat(exception, format, args);
  }

  public static void SafeDebugFormat(this ILogger logger, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.DebugFormat(formatProvider, format, args);
  }

  public static void SafeDebugFormat(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.DebugFormat(exception, formatProvider, format, args);
  }

  #endregion

  #region Error

  public static void SafeError(this ILogger logger, string message)
  {
     if (logger != null)
        logger.Error(message);
  }

  public static void SafeError(this ILogger logger, string message, Exception exception)
  {
     if (logger != null)
        logger.Error(message, exception);
  }

  public static void SafeError(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.Error(format, args);
  }

  public static void SafeErrorFormat(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.ErrorFormat(format, args);
  }

  public static void SafeErrorFormat(this ILogger logger, Exception exception, string format, params object[] args)
  {
     if (logger != null)
        logger.ErrorFormat(exception, format, args);
  }

  public static void SafeErrorFormat(this ILogger logger, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.ErrorFormat(formatProvider, format, args);
  }

  public static void SafeErrorFormat(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.ErrorFormat(exception, formatProvider, format, args);
  }

  #endregion

  #region Fatal

  public static void SafeFatal(this ILogger logger, string message)
  {
     if (logger != null)
        logger.Fatal(message);
  }

  public static void SafeFatal(this ILogger logger, string message, Exception exception)
  {
     if (logger != null)
        logger.Fatal(message, exception);
  }

  public static void SafeFatal(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.Fatal(format, args);
  }

  public static void SafeFatalFormat(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.FatalFormat(format, args);
  }

  public static void SafeFatalFormat(this ILogger logger, Exception exception, string format, params object[] args)
  {
     if (logger != null)
        logger.FatalFormat(exception, format, args);
  }

  public static void SafeFatalFormat(this ILogger logger, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.FatalFormat(formatProvider, format, args);
  }

  public static void SafeFatalFormat(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.FatalFormat(exception, formatProvider, format, args);
  }

  #endregion

  #region Info

  public static void SafeInfo(this ILogger logger, string message)
  {
     if (logger != null)
        logger.Info(message);
  }

  public static void SafeInfo(this ILogger logger, string message, Exception exception)
  {
     if (logger != null)
        logger.Info(message, exception);
  }

  public static void SafeInfo(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.Info(format, args);
  }

  public static void SafeInfoFormat(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.InfoFormat(format, args);
  }

  public static void SafeInfoFormat(this ILogger logger, Exception exception, string format, params object[] args)
  {
     if (logger != null)
        logger.InfoFormat(exception, format, args);
  }

  public static void SafeInfoFormat(this ILogger logger, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.InfoFormat(formatProvider, format, args);
  }

  public static void SafeInfoFormat(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.InfoFormat(exception, formatProvider, format, args);
  }

  #endregion

  #region Warn

  public static void SafeWarn(this ILogger logger, string message)
  {
     if (logger != null)
        logger.Warn(message);
  }

  public static void SafeWarn(this ILogger logger, string message, Exception exception)
  {
     if (logger != null)
        logger.Warn(message, exception);
  }

  public static void SafeWarn(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.Warn(format, args);
  }

  public static void SafeWarnFormat(this ILogger logger, string format, params object[] args)
  {
     if (logger != null)
        logger.WarnFormat(format, args);
  }

  public static void SafeWarnFormat(this ILogger logger, Exception exception, string format, params object[] args)
  {
     if (logger != null)
        logger.WarnFormat(exception, format, args);
  }

  public static void SafeWarnFormat(this ILogger logger, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.WarnFormat(formatProvider, format, args);
  }

  public static void SafeWarnFormat(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] args)
  {
     if (logger != null)
        logger.WarnFormat(exception, formatProvider, format, args);
  }

  #endregion
}

This way we can have our optional logging component with an ‘elegant’ calling syntax (and we don’t pollute all our code with all those nullability checks).

Related Content