Can I add extension methods to an existing static class?

Viewed 239264

I'm a fan of extension methods in C#, but haven't had any success adding an extension method to a static class, such as Console.

For example, if I want to add an extension to Console, called 'WriteBlueLine', so that I can go:

Console.WriteBlueLine("This text is blue");

I tried this by adding a local, public static method, with Console as a 'this' parameter... but no dice!

public static class Helpers {
    public static void WriteBlueLine(this Console c, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.WriteLine(text);
        Console.ResetColor();
    }
}

This didn't add a 'WriteBlueLine' method to Console... am I doing it wrong? Or asking for the impossible?

18 Answers

No. Extension methods require an instance variable (value) for an object. You can however, write a static wrapper around the ConfigurationManager interface. If you implement the wrapper, you don't need an extension method since you can just add the method directly.

 public static class ConfigurationManagerWrapper
 {
      public static ConfigurationSection GetSection( string name )
      {
         return ConfigurationManager.GetSection( name );
      }

      .....

      public static ConfigurationSection GetWidgetSection()
      {
          return GetSection( "widgets" );
      }
 }

It's not possible.

And yes, I think MS made a mistake here.

Their decision does not make sense and forces programmers to write (as described above) a pointless wrapper class.

Here is a good example: Trying to extend static MS Unit testing class Assert: I want 1 more Assert method AreEqual(x1,x2).

The only way to do this is to point to different classes or write a wrapper around 100s of different Assert methods. Why!?

If the decision was being made to allow extensions of instances, I see no logical reason to not allow static extensions. The arguments about sectioning libraries does not stand up once instances can be extended.

Maybe you could add a static class with your custom namespace and the same class name:

using CLRConsole = System.Console;

namespace ExtensionMethodsDemo
{
    public static class Console
    {
        public static void WriteLine(string value)
        {
            CLRConsole.WriteLine(value);
        }

        public static void WriteBlueLine(string value)
        {
            System.ConsoleColor currentColor = CLRConsole.ForegroundColor;

            CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
            CLRConsole.WriteLine(value);

            CLRConsole.ForegroundColor = currentColor;
        }

        public static System.ConsoleKeyInfo ReadKey(bool intercept)
        {
            return CLRConsole.ReadKey(intercept);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteBlueLine("This text is blue");   
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey(true);
        }
    }
}

Nope. Extension method definitions require an instance of the type you're extending. It's unfortunate; I'm not sure why it's required...

You can't add static methods to a type. You can only add (pseudo-)instance methods to an instance of a type.

The point of the this modifier is to tell the C# compiler to pass the instance on the left-side of the . as the first parameter of the static/extension method.

In the case of adding static methods to a type, there is no instance to pass for the first parameter.

I tried to do this with System.Environment back when I was learning extension methods and was not successful. The reason is, as others mention, because extension methods require an instance of the class.

It is not possible to write an extension method, however it is possible to mimic the behaviour you are asking for.

using FooConsole = System.Console;

public static class Console
{
    public static void WriteBlueLine(string text)
    {
        FooConsole.ForegroundColor = ConsoleColor.Blue;
        FooConsole.WriteLine(text);
        FooConsole.ResetColor();
    }
}

This will allow you to call Console.WriteBlueLine(fooText) in other classes. If the other classes want access to the other static functions of Console, they will have to be explicitly referenced through their namespace.

You can always add all of the methods in to the replacement class if you want to have all of them in one place.

So you would have something like

using FooConsole = System.Console;

public static class Console
{
    public static void WriteBlueLine(string text)
    {
        FooConsole.ForegroundColor = ConsoleColor.Blue;
        FooConsole.WriteLine(text);
        FooConsole.ResetColor();
    }
    public static void WriteLine(string text)
    {
        FooConsole.WriteLine(text);
    }
...etc.
}

This would provide the kind of behaviour you are looking for.

*Note Console will have to be added through the namespace that you put it in.

unfotunately NO, you CANNOT extend static classes

https://onecompiler.com/csharp/3xvbe7axg

using System;

namespace HelloWorld
{
  public static class console_extensions {
    public static void EXTENSION(this object item) {
      System.Console.WriteLine("HELLO THERE!");
    }
  }
  
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
            Console.EXTENSION();
            ((Console)null).EXTENSION();
            Console l = new Console();
            l.EXTENSION();
        }
    }
}

output

Compilation failed: 4 error(s), 0 warnings

HelloWorld.cs(16,12): error CS0117: `System.Console' does not contain a definition for `EXTENSION'
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
HelloWorld.cs(17,5): error CS0716: Cannot convert to static type `System.Console'
HelloWorld.cs(18,4): error CS0723: `l': cannot declare variables of static types
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
HelloWorld.cs(18,16): error CS0712: Cannot create an instance of the static class `System.Console'
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)

however you CAN pass null to the extension method

using System;

namespace HelloWorld
{
  public static class static_extensions {
      public static void print(this object item, int data = 0) {
      Console.WriteLine("EXT: I AM A STATIC EXTENSION!");
      Console.WriteLine("EXT: MY ITEM IS: " + item);
      Console.WriteLine("EXT: MY DATA IS: " + data);
      string i;
      if (item == null) {
        i = "null";
      } else {
        i = item.GetType().Name;
      }
      Console.WriteLine("EXT: MY TYPE IS: " + i + "\n");
    }
  }

    public class Program
    {
    
        public static void Main(string[] args)
        {
          // an extension method can be
          //   called directly
          //  (null is an instance)
          static_extensions.print(null);

          // an extension method can also be
          //   called directly with arguments
          //  (null is an instance)
          static_extensions.print(null, 1);
          
          // an extension method can also be
          //   called as part of an instance
          int x = 0; // initialize int
          x.print();
          
          // an extension method can also be
          //   called as part of an instance
          //   and with data
          int x2 = 0; // initialize int
          x2.print(2);
          
          // an extension method can also be
          //   called directly from null
          //   since `null` is an instance
          ((string)null).print();
          
          // an extension method can also be
          //   called directly from null
          //   and with data
          //   since `null` is an instance
          ((string)null).print(4);
        }
    }
}

live example: https://onecompiler.com/csharp/3xvbc8s6w

output:

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 
EXT: MY DATA IS: 0
EXT: MY TYPE IS: null

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 
EXT: MY DATA IS: 1
EXT: MY TYPE IS: null

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 0
EXT: MY DATA IS: 0
EXT: MY TYPE IS: Int32

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 0
EXT: MY DATA IS: 2
EXT: MY TYPE IS: Int32

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 
EXT: MY DATA IS: 0
EXT: MY TYPE IS: null

EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 
EXT: MY DATA IS: 4
EXT: MY TYPE IS: null

Use this

public static class ConfigurationManagerWrapper
 {
  public static ConfigurationSection GetSection( string name )
  {
     return ConfigurationManager.GetSection( name );
  }

  .....

  public static ConfigurationSection GetWidgetSection()
  {
      return GetSection( "widgets" );
  }
 }

Although the methods of Console are static, its static methods Write() and WriteLine() merely redirect the call to Console.Out.Write() and Console.Out.WriteLine() respectively. Out is an instance whose type derives from the abstract class TextWriter. This makes it possible to define extension methods for TextWriter:

public static class ConsoleTextWriterExtensions
{
    public static void WriteBlueLine(this TextWriter writer, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        writer.WriteLine(text);
        Console.ResetColor();
    }

    public static void WriteUppercase(this TextWriter writer, string text)
    {
        writer.Write(text.ToUpper());
    }
}

The method can then be invoked like this:

Console.Out.WriteBlueLine();

And the best part is that the type of the standard error stream instance Console.Error also derives from TextWriter which makes the same extension method also usable for Console.Error:

Console.Error.WriteBlueLine();

This can be quite useful if you have defined an extension method like WriteTable()(for writing a table out to the console) because you can also use it for the error stream or any other object of TextWriter.

Newer versions of C# allow this to be even shorter with a using static statement for Console to get red of the Console. prefix:

using static System.Console;

Out.WriteBlueLine("A blue line");
Error.WriteBlueLine("A blue line");
Related