-3

It makes no sense to me why C# doesn't support static methods & static properties in interfaces. In a brief survey of other SO questions on the issue, I come across a variety of answers ranging from "it's apparently an oversight in the design of C# and/or the CLR, and fixing it would break existing code" all the way to "interfaces are meant to interact with objects, and if you find yourself wanting to use interfaces otherwise, you're obviously lacking grey matter and should probably go back to sweeping floors". This question exhibits the full range of such answers.

I need a family of parsers, each with a method that determines if the assembly file contents passed to it matches its platform type. These are stateless entities; there's no reason to have "objects" of these parsers other than that C# interfaces require class instances. If I rip out all the "static" keywords below, this code compiles without error.

  public interface IParser
  {
     static string platformName { get; }
     static bool isThisPlatform(string asmFileContents);
     static bool parseAsm(string asmFileContents);
  }

  class PIC32MX_GCC_Parser : IParser
  {
     public static string platformName { get { return "PIC32MX_GCC"; } }
     public static bool isThisPlatform(string asmFileContents)
     {
        return false; // stub
     }
     public static bool parseAsm(string asmFileContents)
     {
        return false; // stub
     }
  }

  class M16C_IAR_Parser : IParser
  {
     public static string platformName { get { return "M16C_IAR"; } }
     public static bool isThisPlatform(string asmFileContents)
     {
        return false; // stub
     }
     public static bool parseAsm(string asmFileContents)
     {
        return false; // stub
     }
  }

  IParser[] parsers =
  {
     new PIC32MX_GCC_Parser(),
     new M16C_IAR_Parser()
  };

  public IParser findTheRightParser(string asmFileContents)
  {
     foreach(IParser parser in parsers)
     {
        if (parser.isThisPlatform(asmFileContents))
        {
           Console.WriteLine("Using parser: ", parser.platformName);
           return parser;
        }
     }
     return null;
  }

I'd like to ask why C# won't let me do this, but I know the answer is just "because it doesn't." I know the "workaround" is to just implement them as instance methods which, if necessary, call a static method (which isn't actually necessary in this case).

Since there are a number of people out there (many with high SO rep) who think that putting static methods in interfaces makes no logical sense and if you want to do so there's something wrong with your design, or your head (or both), I'd like some of those people to help me out & give me a good, simple alternative to my code above which uses static methods and doesn't simply "work around" the issue by having instance methods wrap static methods.

Community
  • 1
  • 1
phonetagger
  • 7,701
  • 3
  • 31
  • 55
  • keep them as instance methods and use the Singleton design pattern or use an abstract class – Marco Fatica Feb 23 '16 at 16:33
  • @MarcoFatica - But in this case, there's not even a need for one object. As I mentioned, these are stateless. Ideally there would never even be one object of any of these. – phonetagger Feb 23 '16 at 16:34
  • 1
    For reference: http://stackoverflow.com/a/10837995/106159 – Matthew Watson Feb 23 '16 at 16:37
  • @phonetagger i understand that but because of the limitations of c# those are likely your best two options – Marco Fatica Feb 23 '16 at 16:39
  • 1
    Er, what would your proposed syntax for accessing a static method via an interface (without instantiating an instance of the class) be? – Ben Aaronson Feb 23 '16 at 16:42
  • @BenAaronson - Proposed syntax? I don't really care. I suppose you ought to be able to access a static method via any object of its type, like you can in C++. That is, if you have an object. It would be nice if my `parsers[]` array could be an array of types, instead of an array of instances of those types. I'm not opposed to having empty objects (instances of classes with no non-static members). – phonetagger Feb 23 '16 at 16:50
  • 1
    @phonetagger An array of types? Can you think of a way of doing that which is type-safe? What problem would you be solving? What's the cause of your aversion to instance methods without state? – Ben Aaronson Feb 23 '16 at 16:55
  • I've edited my answer to include the "array of types" request. But I wouldn't recommend using it- the performance will be very bad. – Chris Shain Feb 23 '16 at 16:58
  • If this did work think about this, what if I did `IParser parse = null; var name = parse.platformName;`, what is the value of `name`? – Scott Chamberlain Feb 23 '16 at 16:58
  • @ScottChamberlain - Not sure what point you're trying to make. `name` wouldn't have a value; it would throw a null ref exception. I wasn't arguing that you should be able to call methods of a typeless interface. And I did concede that I would be fine with calling static methods on empty objects (instances of classes with no non-static members). – phonetagger Feb 23 '16 at 17:08
  • I'd implement each as it's own singleton. I see where you are coming from but if you were to try and test code that uses the `static` method you wouldn't be able to mock the interaction and would end up actually running `parseAsm(...)` each time, now I don't know what this does internally but I'm fairly sure I don't want it to happen when I try to test the class that uses the parser. – Stephen Ross Feb 23 '16 at 17:29

2 Answers2

1

There is a need for objects because what you appear to be looking for is dynamic dispatch- you want to be able to call a method on an interface (IParser.Parse), but have the implementation of the method defined by the concrete implementation of the interface. This is classic OOP, and C# (as well as Java) only supports it via instance methods. Singletons eliminate the need for an allocation per call, so that's a good approach. Alternatively you cal use static classes and static methods- but then you are limited to static dispatch, because the caller must know which implementation to call.

In short- it isn't a C# limitation. It's a limitation of most if not all object oriented programming languages.

There are many examples of singleton implementations in the C# literature (for example: http://www.dotnetperls.com/singleton).

To come up with other alternatives requires changing the way that you select your parser. For example, if you wanted to select it via an enum:

enum ParserType {
    PIC32MX_GCC,
    M16C_IAR,
    Other_Parser,
}

Then something like this will work:

public static bool parseAsm(ParserType type, string asmFileContents) {
    switch type {
        case PIC32MX_GCC:
            return PIC32MX_GCC_Parser.ParseAsm(asmFileContents);
        case M16C_IAR:
            return M16C_IAR_Parser.ParseAsm(asmFileContents);
        default:
            throw new NotImplementedException("I dont know this parser type");
    }
}

You can also do what you are already trying to do, via reflection (but the performance will be very bad):

Type[] parsers =
  {
     typeof(PIC32MX_GCC_Parser),
     typeof(M16C_IAR_Parser)
  };

  public Type findTheRightParser(string asmFileContents)
  {
     foreach(Type parser in parsers)
     {
        // You probably want to cache this
        var mi = parser.GetMethod("isThisPlatform", BindingFlags.Static);
        if ((Boolean)mi.Invoke(null, new object[] {asmFileContents}))
        {
           Console.WriteLine("Using parser: ", parser.platformName);
           return parser;
        }
     }
     return null;
  }
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • as of Java 8 static methods are now allowed in interfaces http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html#static – Marco Fatica Feb 23 '16 at 16:46
  • @MarcoFatica Java's static method in the interface looks a lot like C#'s abstract class – Pedro Feb 23 '16 at 16:50
  • @MarcoFatica But not to do what OP wants, which is to have a different implementation depending on the concrete type. – Ben Aaronson Feb 23 '16 at 16:50
0

You can't have static interfaces but you can get the behavior you are looking for if you switch to singletons that redirect to the static fields. Because you use a singleton and the singleton holds no data it has a very low memory overhead, only a few bytes per type.

public interface IParser
{
    string platformName { get; }
    bool isThisPlatform(string asmFileContents);
    bool parseAsm(string asmFileContents);
}

class PIC32MX_GCC_Parser : IParser
{
    private PIC32MX_GCC_Parser()
    {
    }

    public static string platformName { get { return "PIC32MX_GCC"; } }


    public static bool isThisPlatform(string asmFileContents)
    {
        return false; // stub
    }

    public static bool parseAsm(string asmFileContents)
    {
        return false; // stub
    }

    private static readonly PIC32MX_GCC_Parser _instance = new PIC32MX_GCC_Parser();

    public static IParser Instance
    {
        get { return _instance; }
    }

    string IParser.platformName { get { return platformName; } }

    bool IParser.isThisPlatform(string asmFileContents)
    {
        return isThisPlatform(asmFileContents);
    }

    bool IParser.parseAsm(string asmFileContents)
    {
        return parseAsm(asmFileContents);
    }
}

class M16C_IAR_Parser : IParser
{
   //..snip
}

Parser[] parsers =
{
 PIC32MX_GCC_Parser.Instance,
 M16C_IAR_Parser.Instance
};

public IParser findTheRightParser(string asmFileContents)
{
    foreach (IParser parser in parsers)
    {
        if (parser.isThisPlatform(asmFileContents))
        {
            Console.WriteLine("Using parser: ", parser.platformName);
            return parser;
        }
    }
    return null;
}

However if this where me I would just drop the static methods and put all of the data right inside the singleton.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431