630

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?

Amal K
  • 4,359
  • 2
  • 22
  • 44
Leon Bambrick
  • 26,009
  • 9
  • 51
  • 75
  • 3
    Oh well. unfortunate but I think I'll get by. I'm STILL an extension method virgin (in production code anyway). Maybe one day, if i'm lucky. – Andy McCluggage Nov 21 '08 at 17:25
  • I've written a number of HtmlHelper extensions for ASP.NET MVC. Wrote one for DateTime to give me the end of the given date (23:59.59). Helpful when you ask the user to specify an end date, but really want it to be the end of that day. – tvanfosson Nov 21 '08 at 18:25
  • 14
    There's no way to add them currently because the feature doesn't exist in C#. Not because it's impossible _per se_, but because the C# peeps are very busy, were mostly interested in extension methods to make LINQ work and didn't see enough benefit in static extension methods to justify the time they would take to implement. [Eric Lippert explains here](http://stackoverflow.com/a/4914207/230390). – Jordan Gray Oct 31 '12 at 09:54
  • 1
    Just call `Helpers.WriteBlueLine(null, "Hi");` :) – Huseyin Yagli Jul 24 '16 at 14:32

18 Answers18

325

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" );
      }
 }
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • 8
    @Luis -- in context, the idea would be "could I add an extension method to the ConfigurationManager class to get a specific section?" You can't add an extension method to a static class since it requires an instance of the object, but you can write a wrapper class (or facade) that implements the same signature and defers the actual call to the real ConfigurationManager. You can add whatever method you want to the wrapper class so it doesn't need to be an extension. – tvanfosson Feb 18 '10 at 18:35
  • I find it more helpful to just add a static method to the class implementing ConfigurationSection. So given an implementation called MyConfigurationSection, I would call MyConfigurationSection.GetSection(), which returns the section already typed, or null if it does not exist. End result is the same, but it avoids adding a class. – tap Oct 08 '10 at 18:13
  • 1
    @tap - it's only an example, and the first one that came to mind. The single responsibility principle comes into play, though. Should the "container" actually be responsible for interpreting itself from the configuration file? Normally I simply have ConfigurationSectionHandler and cast the output from ConfigurationManager to the appropriate class and don't bother with the wrapper. – tvanfosson Oct 08 '10 at 18:29
  • 7
    For in-house use, I started creating 'X' variants of static classes and structures for adding custom Extensions: 'ConsoleX' contains new static methods for 'Console', 'MathX' contains new static methods for 'Math', 'ColorX' extends the 'Color' methods, etc. Not quite the same, but easy to remember and discover in IntelliSense. – user1689175 Sep 26 '14 at 19:11
  • This is one of the worst C# ideas I have ever heard. The wrapper would have to declare every single static member which exists on the wrapped class. All the method call overheads would double in size. Huge implementation, low performance, high maintenance cost, unacceptable. I can't believe how much likes this answer get. – Xtro Jun 04 '17 at 19:34
  • 1
    @Xtro I agree it's awful, but not worse than not being able to use a test double in it's place or, worse, give up on testing your code because static classes make it so difficult. Microsoft seems to agree with me because it's the reason they introduced the HttpContextWrapper/HttpContextBase classes to get around the static HttpContext.Current for MVC. – tvanfosson Jun 05 '17 at 13:54
  • The statement that extension methods require an instance of an object is false. You can pass on null, which is not an instance of an object. That's why most extension methods require a null check and instance methods never (apart from a very rare exception for finalizers). Though it's true that they don't operate on the type. – Abel Oct 09 '17 at 15:47
  • @Abel - I wasn't being precise for the sake of brevity. They require a value (typically held in a variable) representing an instance of an object, which may be `null` for a reference type. – tvanfosson Oct 09 '17 at 15:51
  • Exactly. Otherwise nothing wrong with your answer, but I do like to be precise, as it's so easy to get confused otherwise ;) – Abel Oct 09 '17 at 15:54
  • @Abel In the context of the question I felt that simply differentiating between an instance variable (value) and a static class reference was sufficient. – tvanfosson Oct 09 '17 at 15:58
93

Can you add static extensions to classes in C#? No but you can do this:

public static class Extensions
{
    public static T Create<T>(this T @this)
        where T : class, new()
    {
        return Utility<T>.Create();
    }
}

public static class Utility<T>
    where T : class, new()
{
    static Utility()
    {
        Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
    }
    public static Func<T> Create { get; private set; }
}

Here's how it works. While you can't technically write static extension methods, instead this code exploits a loophole in extension methods. That loophole being that you can call extension methods on null objects without getting the null exception (unless you access anything via @this).

So here's how you would use this:

    var ds1 = (null as DataSet).Create(); // as oppose to DataSet.Create()
    // or
    DataSet ds2 = null;
    ds2 = ds2.Create();

    // using some of the techniques above you could have this:
    (null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)

Now WHY did I pick calling the default constructor as an example, and AND why don't I just return new T() in the first code snippet without doing all of that Expression garbage? Well todays your lucky day because you get a 2fer. As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it. Damn you Microsoft! However my code calls the default constructor of the object directly.

Static extensions would be better than this but desperate times call for desperate measures.

Carlo V. Dango
  • 13,322
  • 16
  • 71
  • 114
Mr. Obnoxious
  • 987
  • 6
  • 3
  • 3
    I think for Dataset this trick will work, but I doubt that it works for Console class as Console is static class, static types cannot be used as arguments :) – ThomasBecker Apr 28 '15 at 13:55
  • Yeah, I was going to say the same thing. This is pseudo-static extension methods on a non-static class. The OP was an extension method on a static class. – Mark A. Donohoe Sep 27 '15 at 09:14
  • 3
    It's much better and easier to just have some naming convention for such methods like `XConsole`, `ConsoleHelper` and so on. – Alex Zhukovskiy Jan 11 '17 at 10:15
  • 26
    This is a fascinating trick, but the result is smelly. You create a null object, then appear to call a method on it - despite years of being told that "calling a method on a null object causes an exception". It works, but ..ugh... Confusing to anyone maintaining later. I won't downvote, because you have added to the pool of information as to what is possible. But I sincerely hope no one ever uses this technique!! Additional complaint: Don't pass one of these to a method, and expect to get OO subclassing: method called will be type of *parameter declaration* not type of *parameter passed in*. – ToolmakerSteve Jan 24 '18 at 20:16
  • 8
    This is tricky, but I like it. One alternative to `(null as DataSet).Create();` could be `default(DataSet).Create();`. – Teneko Apr 27 '18 at 08:25
  • I like using var to the point of being annoying and doing `var someObject = (SomeObject)null;` or `var someObject = default(SomeObject);`, however, in this case it's really cool that you can do: `SomeObject SomeObject = SomeObject.Create();` or if you want to be hated `SomeObject SomeObject = SomeObject.Create();` ;-) – Brent Rittenhouse Jun 22 '18 at 21:08
  • 1
    The point of extension method to a static class is to make the expression consistent with how we call the extension method usually, that is the static class should be the caller, like this `Helper.SomeMethod()` as we write usually, now we want another extension method `SomeExtensionMethod` we should be able to use it like `Helper.SomeExtensionMethod()`. Your solution is just another way of implementing a wrapper and changes the way we call the extension methods, no more no less. – Hopeless Jul 29 '20 at 23:08
  • 4
    don't understand why this could receive up to 93 upvotes? Because of the fancy generic and reflection-based code, that does not solve anything related to the question. – Hopeless Jul 29 '20 at 23:13
  • 3
    Well said @Hopeless this whole post is riddled with poor supportive arguments, most advocates for Static class extensions are coming across from other languages or development paradigms and so simply do not understand how to achieve their requirement in the native way. But ho this post got this many votes when it doesn't even solve OPs issue, that I'll never understand. – Chris Schaller Mar 14 '21 at 02:08
72

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.

Pang
  • 9,564
  • 146
  • 81
  • 122
Tom Deloford
  • 2,055
  • 1
  • 23
  • 24
  • 24
    I was also trying to extend MS Unit Test class Assert to add Assert.Throws and Assert.DoesNotThrow and faced the same problem. – Stefano Ricciardi Feb 24 '11 at 08:28
  • 3
    Yeah me too :( I thought I can do `Assert.Throws` to the answer http://stackoverflow.com/questions/113395/how-can-i-test-for-an-expected-exception-with-a-specific-exception-message-from-a – CallMeLaNN Jul 14 '11 at 02:55
  • 5
    This post is still as irrelevant today as it was over 10 years ago, there is zero net benefit to extending `Static` classes with additional methods. It always _seems_ like a good idea at first but there are too many reasons in practise why this is an _anti pattern_. There is no _pointless_ wrapper class at all, instead there is a very meaninful and purpose built utility or helper class to keep all of your customised logic in one place. Do not try to replicate _all_ the functions on `Assert` only code your custom functions, Devs call your custom logic when they need to, use Assert for the rest. – Chris Schaller Mar 14 '21 at 02:01
  • 3
    Mistake is the wrong word to use here. Remember Eric's immortal words: _Features are unimplemented by default; C# does not have a feature because no one ever designed, specified, implemented, tested, documented and shipped that feature._ Every feature has a cost, its about prioritizing. – nawfal May 25 '21 at 09:00
  • 2
    Existing extension classes give shorter and cleaner invocations and are compiled into simple extension static method invocations. No cost at runtime. Code is more readable. Code is not more readable because of the NAME of the class. It's more readable because of focusing on the target and skipping the passing of the object as argument. Write less. If you extend a static class there's no readability benefit. You just change the NAME of the class that reduces readability and is in fact a cost. Why we want them? Because we're lazy and don't want to invent new meaningful NAMES. – Harry Sep 09 '21 at 06:14
  • 1
    @ChrisSchaller I find this to be a really bad take. There are many reasons why you would want to extend a static class. Say for example in Unity, the `Debug` class is static. What if you wish to add some extra functionality to the `Debug.Log()` method, such as: Add a verboseness filter so that you don't feel the need to remove some log messages that might clutter up your console, but are still useful for debugging. Right now you have to make do with a wrapper. – creole-basterd Dec 10 '22 at 11:02
  • @creole-basterd : Well, you can't add extra functionality to an existing (non-virtual) method (barring instrumentation) anyway - regardless of whether it's static or not. You are however free to write helper methods in another class that call that existing method in new ways... there's no need for wrapping anything here. Just call your helper methods when you need them and call the originals when you need those... – Oliver Giesen Jan 30 '23 at 01:19
  • 1
    @OliverGiesen The point of extending static classes is to avoid creating further symbol names in the namespace that humans have to remember. Debug.Log(extra_params) is a better function than DebugHelper.Log() because now someone has to remember "DebugHelper", while everyone remembers "Debug" because they use it all the time. The same goes for other static classes. I lost count of how many times this feature would've been super-helpful and would've simplified code significantly. Anything can be an anti-pattern if used incorrectly. – xxbbcc Feb 02 '23 at 18:25
  • @ChrisSchaller I see no reason why extending a type with instance methods would be any different than extending a type with static methods. Do you also think that regular extension methods is an antipattern? If you do then your argument has a much wider scope, if not, I'd be curious about why you think there is any conceptual difference between the two. – Alex Mar 08 '23 at 14:40
  • I love extensions methods for the primary reason that the subject object cannot be easily mistaken. I probably overly abuse them. But it is precisely due to my experience with extension methods that I run into issues that being able to extend statics would cause. This isn't the place to discuss, but I'll write an answer on this and link it back at some time. The end result is that there is no functional benefit to this request, it only makes you think the code looks "cleaner" but in practise it would actually create more technical debt / negative work. I'll explain later ;) – Chris Schaller Mar 09 '23 at 15:12
38

I stumbled upon this thread while trying to find an answer to the same question the OP had. I didn't find the answer I wanted, but I ended up doing this.

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

And I use it like this:

ConsoleColor.Cyan.WriteLine("voilà");
Adel G.Eibesh
  • 481
  • 4
  • 6
  • 3
    In the long run, this will scatter the related functionality across a range of irrelevant parameter types. It will be hard to provide documentation and maintain. – Guney Ozsan Feb 08 '22 at 12:07
24

As of C#7 this isn't supported. There are however discussions about integrating something like that in C#8 and proposals worth supporting.

mbx
  • 6,292
  • 6
  • 58
  • 91
22

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);
        }
    }
}
Pag Sun
  • 845
  • 1
  • 8
  • 11
  • 3
    But this doesn’t solve the problem of needing to reimplement *every* single method from the original static class that you want to keep in your wrapper. It’s still a wrapper, though it does have the merit of needing fewer changes in the code that uses it… – binki Dec 19 '14 at 15:49
18

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

Pang
  • 9,564
  • 146
  • 81
  • 122
  • 6
    It is because an extension method is used to extend an instance of an object. If they didn't do that they would just be regular static methods. – Derek Ekins Jun 06 '09 at 17:15
  • 42
    It'd be nice to do both, wouldn't it? –  Jun 08 '09 at 13:29
  • 1
    @DerekEkins Your statement is technically speaking correct but I would like to object to its relevance. I can execute an extension method on an objects type **even though** there's no instance (i.e. it's `null`). In the extension method `MyExtension(this T self)`, the value of `self` is `nulled`, still being executed. (That, if something, is weird and not widely known.) So why enforce having an instance if then there's no poof, should the instance be nulled?! – Konrad Viltersten Mar 25 '23 at 18:45
7

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.

Brannon
  • 25,687
  • 5
  • 39
  • 44
  • 3
    This kind of answer while technically true does not provide much of anything useful. It's like asking "why cars have 4 wheels?" and someone replying that "they have 4 because otherwise if they had 3, for example, they would be tricycles", which is barely technically true as it is merely trivia about the question, but skips the actual meat of the issue, of why isn't this implemented in any other way that would allow this, and if this isn't already possible in some other way. – Trinidad Dec 08 '21 at 15:52
7

As for extension methods, extension methods themselves are static; but they are invoked as if they are instance methods. Since a static class is not instantiable, you would never have an instance of the class to invoke an extension method from. For this reason the compiler does not allow extension methods to be defined for static classes.

Mr. Obnoxious wrote: "As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it".

New() is compiled to the IL "newobj" instruction if the type is known at compile time. Newobj takes a constructor for direct invocation. Calls to System.Activator.CreateInstance() compile to the IL "call" instruction to invoke System.Activator.CreateInstance(). New() when used against generic types will result in a call to System.Activator.CreateInstance(). The post by Mr. Obnoxious was unclear on this point... and well, obnoxious.

This code:

System.Collections.ArrayList _al = new System.Collections.ArrayList();
System.Collections.ArrayList _al2 = (System.Collections.ArrayList)System.Activator.CreateInstance(typeof(System.Collections.ArrayList));

produces this IL:

  .locals init ([0] class [mscorlib]System.Collections.ArrayList _al,
           [1] class [mscorlib]System.Collections.ArrayList _al2)
  IL_0001:  newobj     instance void [mscorlib]System.Collections.ArrayList::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldtoken    [mscorlib]System.Collections.ArrayList
  IL_000c:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0011:  call       object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type)
  IL_0016:  castclass  [mscorlib]System.Collections.ArrayList
  IL_001b:  stloc.1
Brian Griffin
  • 71
  • 1
  • 2
5

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.

Robert S.
  • 25,266
  • 14
  • 84
  • 116
5

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");
Amal K
  • 4,359
  • 2
  • 22
  • 44
4

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.

2

The following was rejected as an edit to tvanfosson's answer. I was asked to contribute it as my own answer. I used his suggestion and finished the implementation of a ConfigurationManager wrapper. In principle I simply filled out the ... in tvanfosson's answer.

No. Extension methods require an instance of 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 NameValueCollection AppSettings
    {
        get { return ConfigurationManager.AppSettings; }
    }

    public static ConnectionStringSettingsCollection ConnectionStrings
    {
        get { return ConfigurationManager.ConnectionStrings; }
    }

    public static object GetSection(string sectionName)
    {
        return ConfigurationManager.GetSection(sectionName);
    }

    public static Configuration OpenExeConfiguration(string exePath)
    {
        return ConfigurationManager.OpenExeConfiguration(exePath);
    }

    public static Configuration OpenMachineConfiguration()
    {
        return ConfigurationManager.OpenMachineConfiguration();
    }

    public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
    {
        return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
    }

    public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
    {
        return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
    }

    public static void RefreshSection(string sectionName)
    {
        ConfigurationManager.RefreshSection(sectionName);
    }
}
Community
  • 1
  • 1
André C. Andersen
  • 8,955
  • 3
  • 53
  • 79
1

yes, in a limited sense.

public class DataSet : System.Data.DataSet
{
    public static void SpecialMethod() { }
}

This works but Console doesn't because it's static.

public static class Console
{       
    public static void WriteLine(String x)
    { System.Console.WriteLine(x); }

    public static void WriteBlueLine(String x)
    {
        System.Console.ForegroundColor = ConsoleColor.Blue;
        System.Console.Write(.x);           
    }
}

This works because as long as it's not on the same namespace. The problem is that you have to write a proxy static method for every method that System.Console have. It's not necessarily a bad thing as you can add something like this:

    public static void WriteLine(String x)
    { System.Console.WriteLine(x.Replace("Fck","****")); }

or

 public static void WriteLine(String x)
    {
        System.Console.ForegroundColor = ConsoleColor.Blue;
        System.Console.WriteLine(x); 
    }

The way it works is that you hook something into the standard WriteLine. It could be a line count or bad word filter or whatever. Whenever you just specify Console in your namespace say WebProject1 and import the namespace System, WebProject1.Console will be chosen over System.Console as default for those classes in namespace WebProject1. So this code will turn all the Console.WriteLine calls into blue insofar as you never specified System.Console.WriteLine.

Black Dog
  • 71
  • 1
  • 2
  • unfortunately the approach of using a descendant doen't work when the base class is sealed (like many in the .NET class library) – George Birbilis Nov 28 '15 at 21:28
1

You can use a cast on null to make it work.

public static class YoutTypeExtensionExample
{
    public static void Example()
    {
        ((YourType)null).ExtensionMethod();
    }
}

The extension:

public static class YourTypeExtension
{
    public static void ExtensionMethod(this YourType x) { }
}

YourType:

public class YourType { }
Wouter
  • 2,540
  • 19
  • 31
1

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
Clark Kent
  • 75
  • 9
0

I don't really get what people think they'd gain from being able to extend static classes...

What exactly would you be sacrificing by simply doing something like this?

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

//...

MyConsole.WriteBlueLine("I'm so blue...");
Console.WriteLine("...and I'm not.");

It's minimal extra typing effort and as a bonus, it keeps things transparent...

After all, even a regular extension method is just a shorthand for a helper method. It doesn't allow you to do anything to/with a class (instance) that you wouldn't be able to do from a regular method.

Oliver Giesen
  • 9,129
  • 6
  • 46
  • 82
  • 2
    Hi Oliver! It's not a huge advantage but the reason I asked for this was because of discoverability. When someone (i.e., me, a week later...) types "Console.Write..." I wanted to see "Console.WriteBlueLine(" in the intellisense, rather than have to recall "What did I call my console thingy? That's right, `myConsole` ..." etc. – Leon Bambrick Feb 28 '23 at 11:18
-5

You CAN do this if you are willing to "frig" it a little by making a variable of the static class and assigning it to null. However, this method would not be available to static calls on the class, so not sure how much use it would be:

Console myConsole = null;
myConsole.WriteBlueLine("my blue line");

public static class Helpers {
    public static void WriteBlueLine(this Console c, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.WriteLine(text);
        Console.ResetColor();
    }
}
Tenaka
  • 7
  • 1
  • this is exactly what I did. My class is called MyTrace :) – Gishu Oct 13 '10 at 11:00
  • Useful tip. bit of a code smell, but I guess we could hide the null object down in a base class or something. Thanks. – Tom Deloford Feb 19 '11 at 12:14
  • 2
    I cant compile this code. Error 'System.Console': static types cannot be used as parameters – angularrocks.com Feb 22 '11 at 09:23
  • Yes this cannot be done. Damn I thought you were onto something there! Static types cannot be passed as parameters into methods which makes sense I suppose. Let's just hope that MS see the wood from the trees on this one and change it. – Tom Deloford Feb 24 '11 at 14:48
  • 6
    I should have tried compiling my own code! As Tom says, this won't work with static classes. – Tenaka Feb 25 '11 at 15:33