2009-08-06

ConsoleColor extension methods

Sometimes we want to display some text on the console in some specified color (e.g. error in red, warning in yellow, etc). The procedure is often virtually identical, that is, it consists of three steps:

  1. Save the current color.
  2. Write the text on the console.
  3. Restore saved color.

As we can know, the duplication of code is not a good practice, therefore we should extract the first and the last step from the foregoing procedure, and encapsulate it into a nice class. The code located further in this post is an example of such class. The class can help with the mentioned task, and it’s usage is really easy and convenient – look at an example:

using (ConsoleColor.Red.AsForeground())
{
  Console.Error.WriteLine("Error… the application will now generate a lovely BSOD.");
}

The using keyword will guarantee us that the previous color will always be restored (in the compiler-generated finally clause).

In the implementation of the class you can see, that all console-related exception are caught and ignored. If you do not want to ignore these exceptions, you can always delete try-catch clauses, but remember, that the Dispose method must not throw any exception.

And finally, the code of the ConsoleColorExtension class:

C# Download ConsoleColorExtension.cs file
/// <summary>Extension methods for the ConsoleColor enum.</summary>
public static class ConsoleColorExtensions
{
  /// <summary>Provides an easy way to display messages in specified color.</summary>
  /// <param name="foregroundColor">The color in which the messages will be displayed.</param>
  /// <returns>An object which restores previous console foreground color on disposal.</returns>
  /// <example><code>
  /// using (ConsoleColor.Red.AsForeground())
  ///     Console.WriteLine("This should be red.");
  ///
  /// using (ConsoleColor.Cyan.AsForeground())
  /// using (ConsoleColor.Magenta.AsBackground())
  ///     Console.WriteLine("This should be cyan on magenta background.");
  ///
  /// Console.WriteLine("This should be displayed with default colors.");
  /// </code></example>
  public static IDisposable AsForeground(this ConsoleColor foregroundColor)
  {
    if (!Enum.IsDefined(typeof(ConsoleColor), foregroundColor))
      throw new ArgumentOutOfRangeException("foregroundColor");
    return new ConsoleColorizer(foregroundColor, true);
  }

  /// <summary>Provides an easy way to display messages on specified color.</summary>
  /// <param name="backgroundColor">The color on which the messages will be displayed.</param>
  /// <returns>An object which restores previous console background color on disposal.</returns>
  /// <example>See <see cref="M:ConsoleColorExtensions.AsForeground" /> for example.</example>
  public static IDisposable AsBackground(this ConsoleColor backgroundColor)
  {
    if (!Enum.IsDefined(typeof(ConsoleColor), backgroundColor))
      throw new ArgumentOutOfRangeException("backgroundColor");
    return new ConsoleColorizer(backgroundColor, false);
  }

  private sealed class ConsoleColorizer : IDisposable
  {
    public ConsoleColorizer(ConsoleColor cc, bool fore)
    {
      _fore = fore;
      try
      {
        _previousColor = _fore ? Console.ForegroundColor : Console.BackgroundColor;
        if (_fore) Console.ForegroundColor = cc;
        else Console.BackgroundColor = cc;
      }
      catch (Exception e)
      {
        if (!(e is ArgumentException || e is SecurityException || e is IOException)) throw;
      }
    }

    private bool _fore;
    private ConsoleColor? _previousColor;

    public void Dispose()
    {
      if (_previousColor.HasValue)
      {
        try
        {
          if (_fore) Console.ForegroundColor = _previousColor.Value;
          else Console.BackgroundColor = _previousColor.Value;
        }
        catch (Exception e)
        {
          if (!(e is ArgumentException || e is SecurityException || e is IOException)) throw;
        }
      }
      GC.SuppressFinalize(this);
    }
  }
}

Enjoy coloring the console :)

Kick it on DotNetKicks.com