Why can't interfaces specify static methods?

39,108

Solution 1

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.

Solution 2

@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.

Solution 3

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.

Solution 4

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);
    }
}
Share:
39,108
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    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...

  • supercat
    supercat almost 12 years
    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.
  • Dave Cousineau
    Dave Cousineau over 9 years
    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.
  • RLH
    RLH over 9 years
    @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!
  • Jon Skeet
    Jon Skeet over 9 years
    @RLH: Fixed the link (I moved my blog). But no, I don't think anything's changed.
  • ColacX
    ColacX about 9 years
    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.
  • stuzor
    stuzor over 5 years
    @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!
  • Jon Skeet
    Jon Skeet over 5 years
    @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.
  • stuzor
    stuzor over 5 years
    OK right I see, that makes more sense thanks @JonSkeet