0

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.)?

1
  • 2
    static makes only one objecvt - shared between all instances of Foo Commented Feb 3, 2023 at 0:14

2 Answers 2

1

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);   
}
  1. 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.

  1. 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)

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.