Static constructors and field initialization order in C# - c#

This sample from C# in a Nutshell says it writes 0 followed by 3 due to "the field initializer that instantiates a Foo executes before X is initialized to 3".
class Program {
static void Main() { Console.WriteLine (Foo.X); } // 3
}
class Foo
{
public static Foo Instance = new Foo(); //static field 1
public static int X = 3; //static field 2
Foo() => Console.WriteLine (X); // 0
}
My question is, why does this not go into an infinite recursion due to static field 1 which makes a new Foo (which makes a new Foo, which makes a new Foo, etc.)?

Let's have a look at what's going on. BeforeFoo class addressing static fields must be
initialized.
class Program {
static void Main() {
// Before Foo class is addressed (here Foo.X), Foo must be initialized
Console.WriteLine(Foo.X);
}
}
.Net will do it in order they are mentioned in the class declaration:
class Foo
{
// Will be run first
public static Foo Instance = new Foo();
// Will be run second
public static int X = 3;
Foo() => Console.WriteLine(X);
}
So far so good, Instance start its initialization
public static Foo Instance = new Foo();
constructor Foo() called which prints X: Foo() => Console.WriteLine (X); note,
that since X has not been initialized, 0 will be printed.
X will be initialized, it's now 3
Initialization is completed now, and .Net is ready to adddress Foo class
Console.WriteLine(Foo.X);
and 3 will be printed (note the 2nd step of the initialization)

Static fields and properties are shared across all instances of a class, and get initialized in a special constructor called .cctor that gets called when the class is first referenced.
So the compiled code is something similar to
class Foo
{
public static Foo Instance;
public static int X;
.cctor() {
Instance = new Foo();
X = 3;
}
Foo() => Console.WriteLine (X);
}
The call flow would be Foo::.cctor -> Foo::Foo() -> Foo:get_X().
So there is no recursion, but X will have its default value when .cctor is called.

Related

C# Unity > Static instance member not causing constructor to be called

I have noticed a rather weird behaviour in my application I am creating;
I have a class I defined that has a static "instance" variable of the class type.
I would assume that (as per code attached) the constructor would be called.
Alas, it is not, unless I use the Void.get in a non-static field anywhere in my code.
public class Void : TilePrototype {
public static Tile get = new Tile((int)TileEntities.Void);
public static Void instance = new Void();
public Void() {
Debug.Log("created");
id = (int)TileEntities.Void;
isBlocking = true;
register();
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
So when I have something like :
public static TileStack empty = new TileStack(Void.get, Void.get);
the Void class constructor never gets called. But, if I have:
Tile t = Void.get;
Anywhere in my code it will be called.
Why?
Thanks.
This is a really really subtle and nuanced area of C#; basically, you've stumbled into "beforefieldinit" and the difference between a static constructor and a type initializer. You can reasonably ask "when does a static constructor run?", and MSDN will tell you:
It is called automatically before the first instance is created or any static members are referenced.
Except... public static TileStack empty = new TileStack(Void.get, Void.get); isn't a static constructor! It is a static field initializer. And that has different rules, which basically are "I'll run when I must, no later, possibly sooner". To illustrate with an example: the following will not (probably) run your code, because it doesn't have to - there isn't anything demanding the field:
class Program
{
static void Main()
{
GC.KeepAlive(new Foo());
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
However, if we make a tiny tweak:
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
static Foo() { } // <=== added this
}
Now it has a static constructor, so it must obey the "before the first instance is created" part, which means it needs to also run the static field initializers, and so on and so on.
Without this, the static field initializer can be deferred until something touches the static fields. If any of your code actually touches empty, then it will run the static field initializer, and the instance will be created. Meaning: this would also have this effect:
class Program
{
static void Main()
{
GC.KeepAlive(Foo.empty);
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
This ability to defer execution of the static initialization until the static fields are actually touched is called "beforefieldinit", and it is enabled if a type has a static field initializer but no static constructor. If "beforefieldinit" isn't enabled, then the "before the first instance is created or any static members are referenced" logic applies.
Thanks to Marc Gravell's aswer I came up with this contraption (and admittedly I do like the new solution more than the old one, so thanks again!)
Modifications done to the Void class:
public class Void : TilePrototype {
public static Void instance = new Void();
public static Tile get {
get {
return new Tile(instance.id);
}
}
public Void() {
isBlocking = true;
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
}
So as You can see I made the "get" variable a property, so that it's evaluated later, when you actually need the tile, not on construction.
I've changed all "get"s this way.
Second change is in the TilePrototype:
public class TilePrototype {
public static Dictionary<int, TilePrototype> tilePrototypeDictionary = new Dictionary<int, TilePrototype>();
public static void registerPrototype(int id, TilePrototype tp){
tp.id = id;
tilePrototypeDictionary.Add(id, tp);
}
public static bool registered = false;
public static void registerAll(){
if( registered ) return;
registerPrototype(0, Void.instance);
registerPrototype(1, Air.instance);
registerPrototype(2, Floor.instance);
registerPrototype(3, Wall.instance);
(...)
Here I've added the registerPrototype and registerAll functions.
This gives me easy access to all the registered type ids (by say Wall.instance.id) as well as the other way around (from id to instance via the Dictionary)
I also have all registered things in one place, with the possibility of runtime adding more
Overall, much neater, and here I assure that all tiles are registered properly and assigned proper IDs.
Change of ID is simple and in one place and everywhere else, access to this ID is done via a short .instance.id
Thanks again for the help :)

Using static get only property thread safe?

I have this class:
class MyFoo
{
private static readonly string _foo = InitFoo();
public static string Foo
{
get
{
return _foo;
}
}
private static string InitFoo()
{
Debug.WriteLine("InitFoo");
// do some job
return "Foo";
}
}
The private static _foo member is initialized only once when there is a reference to MyFoo.Foo.
The data returned from InitFoo() is large and the method might be time consuming (a matter of 1-2 seconds max), My question, is there a chance that while a thread is referencing MyFoo.Foo another thread that reference it will get an uncompleted or un-initialized data back b/c the InitFoo() is not complete yet?
In other words, Is the above thread-safe? if not how to make it thread-safe (if possible avoid a lock object?)
Thanks.
EDIT: following the comments about Lazy<T> is it now better for thread safety?:
public sealed class MyFoo
{
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static MyFoo() { }
private static readonly Lazy<string> _foo = InitFoo();
public static string Foo
{
get
{
return _foo.Value;
}
}
private static Lazy<string> InitFoo()
{
string s = "Foo";
return new Lazy<string>(() => s);
}
}
Is there a chance that while a thread is referencing MyFoo.Foo another thread that reference it will get an uncompleted or un-initialized data back b/c the InitFoo() is not complete yet?
No. Type initialization is thread-safe:
No other threads get to use your type while it's being initialized by another thread
All writes to memory performed by the initialization thread are made visible to other threads when the initialization has been performed
There's one wrinkle which is that if the same thread that's initializing MyFoo ends up reading MyFoo._foo before it's finished initializing, that will cause a problem. That can be particularly awkward to diagnose if there are types that depend on each other for initialization in a cycle.
Here's an example, with two type initializers that each use a value from the other. They both have static constructors to make the behavior deterministic. (The rules for when types are initialized depend on whether or not they have static constructors.)
using System;
public class Program
{
public static void Main(string[] args)
{
// Determine which type to initialize first based on whether there
// are any command line arguemnts.
if (args.Length > 0)
{
Class2.DoNothing();
}
Console.WriteLine($"Class1.Value1: {Class1.Value1}");
Console.WriteLine($"Class2.Value2: {Class2.Value2}");
}
}
public class Class1
{
public static readonly string Value1 =
$"When initializing Class1.Value1, Class2.Value2={Class2.Value2}";
static Class1() {}
}
public class Class2
{
public static readonly string Value2 =
$"When initializing Class2.Value2, Class2.Value2={Class1.Value1}";
static Class2() {}
public static void DoNothing() {}
}
Running this without any command line arguments, Class1 starts initializing first, which in turn initializes Class2:
Class1.Value1: When initializing Class1.Value1, Class2.Value2=When initializing Class2.Value2, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=
With any command line argument, we initialize Class2 first, which in turn initializes Class1:
Class1.Value1: When initializing Class1.Value1, Class2.Value2=
Class2.Value2: When initializing Class2.Value2, Class2.Value2=When initializing Class1.Value1, Class2.Value2=

Why it is a StackOverFlow Exception?

Why following code throws StackoverflowException?
class Foo
{
Foo foo = new Foo();
}
class Program
{
static void Main(string[] args)
{
new Foo();
}
}
in Main you create a new Foo object, invoking its constructor.
inside Foo constructor, you create a different Foo instance invoking again Foo constructor.
This lead to infinite recursion and end with a StackOverflow exception
Well, let´s see:
Program runs main which executes new Foo();;
new Foo() creates new Foo instance, including Foo foo field
Foo foo = new Foo();executes new Foo (go to step 2)

Static Constructor and singleton

My friend told me that the following is one of the ways to create singleton design pattern in C#
public class class1{
public static class1 Obj { get; private set; }
static class1()
{
Obj = new class1();
}
}
He told me that the static constructor runs only one time in application, so only one instance of class1 will be created,
but I see that I have to add this if(Obj==null) to check the existence of object
public class class1{
public static class1 Obj { get; private set; }
static class1()
{
**if(Obj==null)**
Obj = new class1();
}
}
which code is correct?
Assuming that the only place where Obj is set is in the static constructor, the first code snippet is correct; the second code snippet is redundant.
Since static constructors run only once per class. If there is no other path to set Obj, its value will always be null at the beginning of the static constructor. Therefore, the check if(Obj==null) will always succeed, which makes it redundant.
The static constructor will only ever be called once, at some point prior to the static variables being allocated.
Which means that your friend is correct, you do not need the if statement - it is redundant.
This is because you cannot call a static constructor manually, it will only be called once, at the start of run-time.
Further reading : https://stackoverflow.com/a/4506997/617485

Why isn't the static constructor hit first?

I have the below code and I have only two simple questions which are normal to expect in the behavior of the program below, which I am not seeing unfortunately:
Static constructor in any class should be the first one to be hit soon after static fields being hit. Then only instance constructor. But what I am seeing is, the debug first goes to the public constructor. Sad thing. Why?
Although: the output of the program is:
This is Staticcc...
1
...Which is correct.
I kept a break point in the Static constructor start, but when I debug it only shows break point in the end brace of static constructor. Why?
Sample code:
public sealed class B : A, C
{
public int? m = 0;
public B()
{
m = 1;
}
private B(int a, int b)
{
m = 2;
}
protected B(int x, int y, int z)
{
m = 3;
}
static B()
{
Console.WriteLine("THis is staticcc");
}
public static B b = new B();
public static B BC
{
get
{
return b;
}
}
static void Main()
{
Console.WriteLine(B.BC.m);
Console.ReadKey();
}
}
public interface C
{
}
public class A
{
//private A()
//{
//}
}
This is the problem:
public static B b = new B();
Static field initializers are executed before the static constructor is executed. From the C# spec section 10.5.5.1:
If a static constructor (10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor.
Your static field initializer calls your instance constructor, therefore the instance constructor is the first thing to execute.
Although: the output of the program is This is Staticcc... then 1...Which is correct.
Yes, because all of the initialization happens as part of evaluating B.BC.m in Main.
If you add Console.WriteLine("Instance Constructor"); into your constructor, you'll see:
Instance Constructor
THis is staticcc
1
If that doesn't help, think of Main as being this:
int tmp = B.BC.m; // This prints initialization bits
Console.WriteLine(tmp); // This prints 1
That is because this line is ran before the static constructor:
public static B b = new B();
Your first line in the static constructor (the part you don't see, but is actually there) is actually calling the constructor of B. That is the reason you don't see the static constructor hit first.
If you would write it like this, you would see the static constructor hit first:
static B()
{
Console.WriteLine("THis is staticcc");
b = new B();
}
public static B b;

Categories