Why Can't I Declare C# Methods Virtual and Static

Why can't I declare C# methods virtual and static?

Virtual static methods don't make sense. If I call HelperClass.HelperMethod();, why would I expect some random subclass' method to be called? The solution really breaks down when you have 2 subclasses of HelperClass - which one would you use?

If you want to have overrideable static-type methods you should probably go with:

  • A singleton, if you want the same subclass to be used globally.
  • A tradition class hierarchy, with a factory or dependency injection, if you want different behavior in different parts of your application.

Choose whichever solution makes more sense in your situation.

C# virtual static method

virtual means the method called will be chosen at run-time, depending on the dynamic type of the object. static means no object is necessary to call the method.

How do you propose to do both in the same method?

Why can't interfaces specify static methods?

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.

C# Alternative to virtual static methods and static sub classes

This could serve your purpose, though I certainly would include some exception handling and accompany its implementation with a great deal of documentation as to why and how it works.

When the static constructor for Base is run (once) all assemblies that are currently loaded in the app domain are catalogued, selecting the types that derive from Base. Iterating over those, we run the static constructors. It is worth noting though, that this no longer guarantees the cctor for each implementation will be run exactly once, logic would have to be added to each of them to re-make that assertion. Moreover, types that are loaded after the cctor for Base has been run would not be initialized by calls to methods in Base

To simulate virtual methods, use the new keyword to hide the base method. You can call the base method by qualifying it with the declaring class's name (like in class B in the example)

using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
public class Base
{
static Base()
{
Console.WriteLine("Base cctor");

var thisType = typeof (Base);
var loadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes());
var derivations = loadedTypes.Where(thisType.IsAssignableFrom);

foreach(var derivation in derivations)
{
RuntimeHelpers.RunClassConstructor(derivation.TypeHandle);
}
}

public static void Foo()
{
Console.WriteLine("Bar");
}
}

public class A : Base
{
static A()
{
Console.WriteLine("A cctor");
}
}

public class B : Base
{
static B()
{
Console.WriteLine("B cctor");
}

public new static void Foo()
{
Console.WriteLine("Bar!!");
Base.Foo();
}
}

class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}

EDIT

Another option lies in the CRTP (or CRGP in the C# paradigm) or curiously recurring template (generic) parameter pattern

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
public class Base<T>
where T : Base<T>
{
static Base()
{
RuntimeHelpers.RunClassConstructor(typeof (T).TypeHandle);
}

public static void Foo()
{
Console.WriteLine("Bar");
}
}

public class Base : Base<Base>
{
}

public class A : Base<A>
{
static A()
{
Console.WriteLine("A cctor");
}
}

public class B : Base<B>
{
static B()
{
Console.WriteLine("B cctor");
}

public new static void Foo()
{
Console.WriteLine("Bar!!");
Base<B>.Foo();
}
}

class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}

In this case, when we call a static method on A we're really calling it on Base<A> which is different than Base<B> or Base so we can actually determine how the method was called and run the appropriate cctor.

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

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.

C# virtual (or abstract) static methods

No, you cannot override a static method. "static" also means that it is statically bound by the compiler, so the actual method to be called is not found at runtime, but bound at compile time.

What you should do is make the class non-static. Make the method virtual and override it and make full benefit of real inheritance. Then, if you really need it, make a static entry point to a reference of your class. For instance a static factory, singleton (it's an anti-pattern in most of the cases but is as good as a static class) or just a static property.

Why are C# interface methods not declared abstract or virtual?

For the interface, the addition of the abstract, or even the public keywords would be redundant, so you omit them:

interface MyInterface {
void Method();
}

In the CIL, the method is marked virtual and abstract.

(Note that Java allows interface members to be declared public abstract).

For the implementing class, there are some options:

Non-overridable: In C# the class doesn't declare the method as virtual. That means that it cannot be overridden in a derived class (only hidden). In the CIL the method is still virtual (but sealed) because it must support polymorphism regarding the interface type.

class MyClass : MyInterface {
public void Method() {}
}

Overridable: Both in C# and in the CIL the method is virtual. It participates in polymorphic dispatch and it can be overridden.

class MyClass : MyInterface {
public virtual void Method() {}
}

Explicit: This is a way for a class to implement an interface but not provide the interface methods in the public interface of the class itself. In the CIL the method will be private (!) but it will still be callable from outside the class from a reference to the corresponding interface type. Explicit implementations are also non-overridable. This is possible because there's a CIL directive (.override) that will link the private method to the corresponding interface method that it's implementing.

[C#]

class MyClass : MyInterface {
void MyInterface.Method() {}
}

[CIL]

.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}

In VB.NET, you can even alias the interface method name in the implementing class.

[VB.NET]

Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class

[CIL]

.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}

Now, consider this weird case:

interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }

If Base and Derived are declared in the same assembly, the compiler will make Base::Method virtual and sealed (in the CIL), even though Base doesn't implement the interface.

If Base and Derived are in different assemblies, when compiling the Derived assembly, the compiler won't change the other assembly, so it will introduce a member in Derived that will be an explicit implementation for MyInterface::Method that will just delegate the call to Base::Method.

So you see, every interface method implementation must support polymorphic behavior, and thus must be marked virtual on the CIL, even if the compiler must go through hoops to do it.

Calling descendant virtual methods from static method

To invoke a non static method from a static method, you have to provide an instance as the static method isn't bound to this

Then, after your edit, your question made me think of the curiously recurring template pattern in C++.

I never tried myself to use it in C# but you have have a look here, which would give you something like:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication3
{
public abstract class Foo<T> where T : Foo<T>, new()
{
public static void StaticMethod()
{
T t = new T();
t.VirtualMethod();
}

public abstract void VirtualMethod();
}

public class Bar : Foo<Bar>
{
public override void VirtualMethod()
{
System.Console.WriteLine("virtual from static!!!!");
}
}
class Program
{
static void Main(string[] args)
{
Bar.StaticMethod();
}
}
}

And prints out the intended "virtual from static!!!!" message in the console.



Related Topics



Leave a reply



Submit