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 I was wondering if someone here might be able to offer a nice clear explanation?
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.
To add to the previous explanations, static method calls are bound to a specific method at compile-time, which rather rules out polymorphic behavior.
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 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.
@chook and @lassevk thanks for your explanations. They definately clear things up
My opinionated answer is because C# and java don't have proper OO
This works fine in ruby and probably python, where everything actually is an object
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.
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.
The abstract methods are implicitly virtual. Static methods require instance, but abstract 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).
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"?
Is it only me that feels that there are situations where static abstract functions are ESSENTIAL?
How can you enforce your inherited classes to implement an override for a particular static function without the abstract keyword? And without implementing an interface?
For me it s not a matter of polymorphism..since i WILL write A.getLegs() instead of Base.getLegs(). But i will expect that the A class DOES have a static function getLegs. So it 's a matter of enforcing the inherited class to actually have the function defined in it's superclass. How can i do that?