Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to ensure a base class's static constructor is called?

The documentation on static constructors in C# says:

A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced.

That last part (about when it is automatically called) threw me for a loop; until reading that part I thought that by simply accessing a class in any way, I could be sure that its base class's static constructor had been called. Testing and examining the documentation have revealed that this is not the case; it seems that the static constructor for a base class is not guaranteed to run until a member of that base class specifically is accessed.

Now, I guess in most cases when you're dealing with a derived class, you would construct an instance and this would constitute an instance of the base class being created, thus the static constructor would be called. But if I'm only dealing with static members of the derived class, what then?

To make this a bit more concrete, I thought that the code below would work:

abstract class TypeBase {     static TypeBase()     {         Type<int>.Name = "int";         Type<long>.Name = "long";         Type<double>.Name = "double";     } }  class Type<T> : TypeBase {     public static string Name { get; internal set; } }  class Program {     Console.WriteLine(Type<int>.Name); } 

I assumed that accessing the Type<T> class would automatically invoke the static constructor for TypeBase; but this appears not to be the case. Type<int>.Name is null, and the code above outputs the empty string.

Aside from creating some dummy member (like a static Initialize() method that does nothing), is there a better way to ensure that a base type's static constructor will be called before any of its derived types is used?

If not, then... dummy member it is!

like image 909
Dan Tao Avatar asked Jan 10 '11 22:01

Dan Tao


People also ask

How do you call a static class constructor?

A static constructor cannot be called directly and is only meant to be called by the common language runtime (CLR). It is invoked automatically. The user has no control on when the static constructor is executed in the program. A static constructor is called automatically.

When and how static constructor is called?

Static constructor are called automatically before the first instance is created or any static members are referenced. A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only.

How do you call a static method in base class?

A static method is the one which you can call without instantiating the class. If you want to call a static method of the superclass, you can call it directly using the class name.

Which constructor will be called first static or normal constructor?

Static constructors are used to initialize the static members of the class and are implicitly called before the creation of the first instance of the class. Non-static constructors are used to initialize the non-static members of the class.


2 Answers

You may call static constructor explicity, so you will not have to create any methods for initialization:

System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof (TypeBase).TypeHandle); 

You may call it in static constructor of derived class.

like image 77
petro.sidlovskyy Avatar answered Oct 07 '22 15:10

petro.sidlovskyy


As others have noted, your analysis is correct. The spec is implemented quite literally here; since no member of the base class has been invoked and no instance has been created, the static constructor of the base class is not called. I can see how that might be surprising, but it is a strict and correct implementation of the spec.

I don't have any advice for you other than "if it hurts when you do that, don't do that." I just wanted to point out that the opposite case can also bite you:

class Program  {   static void Main(string[] args)   {           D.M();   }        } class B  {    static B() { Console.WriteLine("B"); }   public static void M() {} }  class D: B  {    static D() { Console.WriteLine("D"); } } 

This prints "B" despite the fact that "a member of D" has been invoked. M is a member of D solely by inheritance; the CLR has no way of distinguishing whether B.M was invoked "through D" or "through B".

like image 39
Eric Lippert Avatar answered Oct 07 '22 15:10

Eric Lippert