42

I know this question has been asked over and over, but I can't seem to find good enough answers. So to make it clear what I'm trying to know, I'll split this in two questions:

  1. Why can't interfaces have static method signatures? I'll try to preempt the non-answers asking why in the world I would want to do this with the following: I would want to be able to statically invoke GetDbConnectionType() on SqliteCodeGenerator and MssqlCodeGenerator:

    interface ICodeGenerator
    {
        // this is the method I would like to be static:
        string GetDbConnectionType();
    }
    
    abstract class CodeGeneratorBase : ICodeGenerator
    {
        public abstract string GetDbConnectionType();
    
        public void GenerateSomeCode(StringBuilder s)
        {
            s.AppendLine("var foo = new " + GetDbConnectionType() + "();");
        }
    }
    
    class SqliteCodeGenerator : CodeGeneratorBase
    {
        public override string GetDbConnectionType()
        {
            return "SQLiteConnection";
        }
    }
    
    class MssqlCodeGenerator : CodeGeneratorBase
    {
        public override string GetDbConnectionType()
        {
            return "SqlConnection";
        }
    }
    
  2. On the other hand, and this is the matter of this second question, if you know of a good alternative to reach the aforementioned goal, then by all means...

  • Wrong dup, it's this one: http://stackoverflow.com/questions/248263/why-cant-i-declare-c-sharp-methods-virtual-and-static – Joe May 31 '12 at 17:21
  • possible duplicate of [Why shouldn't C#(or .NET) allow us to put a static/shared method inside an interface?](http://stackoverflow.com/questions/1062468/why-shouldnt-cor-net-allow-us-to-put-a-static-shared-method-inside-an-inter) – nawfal Jan 02 '14 at 16:39
  • Possible duplicate of [Why can't I declare C# methods virtual and static?](https://stackoverflow.com/questions/248263/why-cant-i-declare-c-sharp-methods-virtual-and-static) –  Jan 29 '18 at 11:36

6 Answers6

66

Suppose you could specify in an interface that a type had to have a particular static method... how would you call it? Polymorphism works through instances - whereas static members explicitly don't use instances.

Now, having said that, there's one situation in which I can see static interface members working: generic types. For example:

// This isn't valid code...
public void Foo<T>() where T : ICodeGenerator
{
    string type = T.GetDbConnectionType();
}

That would call the static member on the concrete type T.

I've blogged more about this, but I suspect the benefit doesn't justify the complexity.

In terms of alternatives - usually you'd have another interface, and have separate types to implement that interface. That works well in some contexts, but not in others.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Members of generic type `T:BaseType` are always bound to `BaseType`, rather than `T`. If those members in `BaseType` are virtual, the binding is to the vtable slots defined in `BaseType`. Virtual members invoked on a reference of type `T` are dispatched through the slot numbers defined by type `BaseType`; type `T` plays no role in the dispatch. It might be useful to allow types to declare and override virtual static methods such that, with a little more magic, `T.VirtualStaticMethod()` would be dispatched via `T`'s vtable , using a slot defined in `BaseType`, but it'd be a big change. – supercat May 31 '12 at 18:15
  • 5
    Additionally, there is the benefit of forcing the type to implement the static members, as well as querying for types that implement the interface, and being able to expect a static method to exist. – Dave Cousineau Aug 30 '14 at 22:17
  • @JonSkeet, your blog post is broken. Do you have an update? This is exactly what I need. How has this changed in the past three years if the former blog post is no longer pertinent. Thank you! – RLH Jan 09 '15 at 16:16
  • @RLH: Fixed the link (I moved my blog). But no, I don't think anything's changed. – Jon Skeet Jan 09 '15 at 16:19
  • 1
    I found myself needing a static interface, only so that i can avoid creating a pointless instance of the type. but i have to agree static interfaces might cause needless complexity. – ColacX May 27 '15 at 08:29
  • @JonSkeet you say polymorphism works through instances.. what exactly do you mean by that? Subclass types inherit the ability to call static properties and methods from their super class - isn't that polymorphism working on types as well? i.e.: class Foo { public static int Number = 1; } class Bar : Foo { } Bar.Number <--- this is possible. And when you talk about justifying the complexity - do you mean the complexity to the .NET developers or complexity to the programmers using it? It still seems to me that static types on interfaces would be super useful. Thanks in advance! – stuzor Nov 21 '18 at 10:23
  • 1
    @stuzor: No, that's not polymorphism - at least not how I'd use the term. I consider polymorphism to be the ability for the implementation of a method to be determined at execution time - which is based on the instance it is called on. That goes for interface implementations, abstract method implementations, and virtual method overrides. The complexity is in terms of the language specification, and developers needing to learn that extra information. It's possible that something *like* this may happen in the future, but only in terms of generic type parameters, as per my answer. – Jon Skeet Nov 21 '18 at 21:03
  • OK right I see, that makes more sense thanks @JonSkeet – stuzor Nov 22 '18 at 01:28
7

@JonSkeet: It's possible to create a static interface member in CIL, so I'm afraid your first statement is misleading. I assume it was omitted from C# as a design choice by the Microsoft team to encourage correct usage of interfaces.

The best way to get this functionality is probably with extension methods, these will allow you to add a method to all inheritors of your interface or to a specific implementation of that interface however you need to write a separate class to hold the implementation of the extension method which (if not planned for) can be easy to lose track of.

Dead.Rabit
  • 1,965
  • 1
  • 28
  • 46
1

Jon's answer covers pretty much everything so my answer only includes a possible work around using the .NET configuration API. It requires a bit of syntax overhead but it does give you static access to the instance.

interface IStorage
{
    void Store(string item);
}

static class Storage
{
    private static readonly IStorage _instance;

    static Storage()
    {
        var storageTypeString = ConfigurationManager.AppSettings["storageTypeString"];
        var storageType = Type.GetType(storageTypeString, true);
        _instance = (IStorage)Activator.CreateInstance(storageType);
    }

    public static void Store(string item)
    {
        _instance.Store(item);
    }
}
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
1

It might be somewhat helpful if an interface could specify a static class, such that members of that class would be seen by the compiler as static members of that interface. Thus, instead of having to use static class Enumerable<T> to get Enumerable<T>.Default, one could instead syntactically specify IEnumerable<T>.Default.

It would be even more helpful if an interface could specify that some such static methods should be usable in a fashion similar to extension methods, but without the weird scoping rules associated with them (so an interface could appear to offer multiple "convenience" overloads for some member functions without requiring all of the implementations to provide them).

It would be extremely helpful if, combined with such a feature, interface methods could be declared "optional", such that when an implementation provided a method it would be used, and when it did not the extension-ish method would be automatically substituted. This would probably require changes to the CLR, however.

In any case, because interfaces do not include static classes, the best one can do is provide static classes which users of the interface will find helpful, even though the compiler will regard those classes and the interfaces as entirely independent entities.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

I know this is old, but actually you can with static functions declared in a static class outside of a name space.

but they way your putting it you would just make the function static in the abstract class

to do it from an interface you do this

public static class Interfacefunction{
  public static string GetDbConnectionType(this ICodeGenerator me)
  {
      // this is the method I would like to be static:
      // you can even get access to me
      return "SQLiteConnection";
  }
}
0

A sort of workaround (though it may actually be better this way) for this I've decided to use is to use a static instance instead of a static interface.

Rather than:

// does not compile
ISomeInterface {
   static void DoSomething();
   static bool TestSomething(string pValue);
   // etc... 
}

static class SomeStaticClass : ISomeInterface {
   public static void DoSomething() {
   }

   public static bool TestSomething(string pValue) {
   }
}

Define a class (make it generic if the logic must vary between classes that you use it with):

sealed class SomeClass {
   public void DoSomething() {
      // reusable implementation
   }

   public bool TestSomething(string pValue) {
      // reusable implementation
   }
}

and give a static instance of that class to your static class:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();
}

The only issue is that you have to decide whether to expose a property to the static instance:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();

   public static SomeClass SomeProperty { get { return sSomeClass; } }
}

...

SomeStaticClass.SomeProperty.DoSomething();
if (SomeStaticClass.SomeProperty.TestSomething(someValue))
   ...

or to wrap its methods:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();

   public static void DoSomething() {
      sSomeClass.DoSomething();
   }

   public static bool TestSomething(string pValue) {
      sSomeClass.TestSomething(pValue);
   }
}

...

SomeStaticClass.DoSomething();
if (SomeStaticClass.TestSomething(someValue))
   ...
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80