Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does static field initialization work in C#?

Should static field initialization be completed before constructor is called?

The following program provides output that seems incorrect to me.

new A() _A == null static A() new A() _A == A 

The code:

public class A {     public static string _A = (new A()).I();      public A()     {         Console.WriteLine("new A()");         if (_A == null)             Console.WriteLine("_A == null");         else             Console.WriteLine("_A == " + _A);     }      static A()     {         Console.WriteLine("static A()");     }      public string I()     {         return "A";     } }  class Program {     static void Main(string[] args)     {        var a = new A();     } } 
like image 935
Prankster Avatar asked Apr 02 '09 17:04

Prankster


People also ask

How do you initialize a static field?

The only way to initialize static final variables other than the declaration statement is Static block. A static block is a block of code with a static keyword. In general, these are used to initialize the static members. JVM executes static blocks before the main method at the time of class loading.

How do static fields work?

A static field is in programming languages is the declaration for a variable that will be held in common by all instances of a class. The static modifier determines the class variable as one that will be applied universally to all instances of a particular class.

Can a static variable be initialized in a constructor C#?

You can define a static field using the static keyword. If you declare a static variable in a class, if you haven't initialized it, just like with instance variables compiler initializes these with default values in the default constructor. Yes, you can also initialize these values using the constructor.

What is meant by static initialization of objects?

You initialize a static object with a constant expression, or an expression that reduces to the address of a previously declared extern or static object, possibly modified by a constant expression.


2 Answers

This is correct.

Your static initializers, then the static constructor is run before your standard constructor, but when it runs, it's using new A(), so passing through your non-static constructor path. This causes the messages you see.

Here is the full path of execution:

When you first call var a = new A(); in your program, this is the first time A is accessed.

This will fire off the static initialization of A._A

At this point, A._A constructs with _A = (new A()).I();

This hits

 Console.WriteLine("new A()"); if (_A == null)     Console.WriteLine("_A == null");         

since at this point, _A hasn't been set with the returned, constructed type (yet).

Next, the static constructor A { static A(); } is run. This prints the "static A()" message.

Finally, your original statement (var a = new A();) is executed, but at this point, the statics are constructed, so you get the final print.

like image 67
Reed Copsey Avatar answered Oct 11 '22 18:10

Reed Copsey


One extra side note - the C# specification (I'm looking at 4.0, but it's there in 3.0 too) says in 10.5.5.1 Static Field Initialization:

If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

You have a static constructor, so the "Otherwise" clause does not apply. But I think it's relevant information to your question to know that if you don't have a static constructor, the static field initializers can be executed 'at an implementation-dependent time'. This could matter if your static field initializer is doing some type of data initialization or object creation which you rely on without accessing the static field itself.

It is esoteric, I guess, but I saw it happen today as the 'implementation-dependent time' appears to have changed between C# 3.0 and 4.0 - at least for the situation I was looking at. The easy solution of course is simple - just add a static constructor...

like image 43
Hugh Robinson Avatar answered Oct 11 '22 17:10

Hugh Robinson