.net - Why can't I have abstract static methods in C#?


Translate

I've been working with providers a fair bit lately, and I came across an interesting situation where I wanted to have an abstract class that had an abstract static method. I read a few posts on the topic, and it sort of made sense, but is there a nice clear explanation?


Всички отговори
  • Translate

    Static methods are not instantiated as such, they're just available without an object reference.

    A call to a static method is done through the class name, not through an object reference, and the Intermediate Language (IL) code to call it will call the abstract method through the name of the class that defined it, not necessarily the name of the class you used.

    Let me show an example.

    With the following code:

    public class A
    {
        public static void Test()
        {
        }
    }
    
    public class B : A
    {
    }
    

    If you call B.Test, like this:

    class Program
    {
        static void Main(string[] args)
        {
            B.Test();
        }
    }
    

    Then the actual code inside the Main method is as follows:

    .entrypoint
    .maxstack 8
    L0000: nop 
    L0001: call void ConsoleApplication1.A::Test()
    L0006: nop 
    L0007: ret 
    

    As you can see, the call is made to A.Test, because it was the A class that defined it, and not to B.Test, even though you can write the code that way.

    If you had class types, like in Delphi, where you can make a variable referring to a type and not an object, you would have more use for virtual and thus abstract static methods (and also constructors), but they aren't available and thus static calls are non-virtual in .NET.

    I realize that the IL designers could allow the code to be compiled to call B.Test, and resolve the call at runtime, but it still wouldn't be virtual, as you would still have to write some kind of class name there.

    Virtual methods, and thus abstract ones, are only useful when you're using a variable which, at runtime, can contain many different types of objects, and you thus want to call the right method for the current object you have in the variable. With static methods you need to go through a class name anyway, so the exact method to call is known at compile time because it can't and won't change.

    Thus, virtual/abstract static methods are not available in .NET.


  • Translate

    Static methods cannot be inherited or overridden, and that is why they can't be abstract. Since static methods are defined on the type, not the instance, of a class, they must be called explicitly on that type. So when you want to call a method on a child class, you need to use its name to call it. This makes inheritance irrelevant.

    Assume you could, for a moment, inherit static methods. Imagine this scenario:

    public static class Base
    {
        public static virtual int GetNumber() { return 5; }
    }
    
    public static class Child1 : Base
    {
        public static override int GetNumber() { return 1; }
    }
    
    public static class Child2 : Base
    {
        public static override int GetNumber() { return 2; }
    }
    

    If you call Base.GetNumber(), which method would be called? Which value returned? Its pretty easy to see that without creating instances of objects, inheritance is rather hard. Abstract methods without inheritance are just methods that don't have a body, so can't be called.


  • Translate

    Another respondent (McDowell) said that polymorphism only works for object instances. That should be qualified; there are languages that do treat classes as instances of a "Class" or "Metaclass" type. These languages do support polymorphism for both instance and class (static) methods.

    C#, like Java and C++ before it, is not such a language; the static keyword is used explicitly to denote that the method is statically-bound rather than dynamic/virtual.


  • Translate

    To add to the previous explanations, static method calls are bound to a specific method at compile-time, which rather rules out polymorphic behavior.


  • Translate

    Here is a situation where there is definitely a need for inheritance for static fields and methods:

    abstract class Animal
    {
      protected static string[] legs;
    
      static Animal() {
        legs=new string[0];
      }
    
      public static void printLegs()
      {
        foreach (string leg in legs) {
          print(leg);
        }
      }
    }
    
    
    class Human: Animal
    {
      static Human() {
        legs=new string[] {"left leg", "right leg"};
      }
    }
    
    
    class Dog: Animal
    {
      static Dog() {
        legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
      }
    }
    
    
    public static void main() {
      Dog.printLegs();
      Human.printLegs();
    }
    
    
    //what is the output?
    //does each subclass get its own copy of the array "legs"?
    

  • Translate

    We actually override static methods (in delphi), it's a bit ugly, but it works just fine for our needs.

    We use it so the classes can have a list of their available objects without the class instance, for example, we have a method that looks like this:

    class function AvailableObjects: string; override;
    begin
      Result := 'Object1, Object2';
    end; 
    

    It's ugly but necessary, this way we can instantiate just what is needed, instead of having all the classes instantianted just to search for the available objects.

    This was a simple example, but the application itself is a client-server application which has all the classes available in just one server, and multiple different clients which might not need everything the server has and will never need an object instance.

    So this is much easier to maintain than having one different server application for each client.

    Hope the example was clear.


  • Translate

    The abstract methods are implicitly virtual. Abstract methods require an instance, but static methods do not have an instance. So, you can have a static method in an abstract class, it just cannot be static abstract (or abstract static).