# Static Initialization

The way static fields are initialized has been changed across .net framework version. As the framework matured, static fields have become initialized more lazily.

Today I will show a quick comparison between ```.net472``` and ```.netcoreapp3.0``` focused on static field initialization. I will use the following application to demonstrate the issue.

```csharp
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Start");
        var test = new Test();
        test.DoWork();
        Console.WriteLine("Start work");
        test.DoWork2();
    }
}

public class Test
{
    private static readonly Logger logger = new Logger();
    public Test() => Console.WriteLine("TestCtr");
    public void DoWork() => Console.WriteLine("Working...");
    public void DoWork2()
    {
        Console.WriteLine("Working2...");
        logger.Log("Completing work");
    }
}

public class Logger
{
    public Logger() => Console.WriteLine("LoggerCtr");
    public void Log(string message) => Console.WriteLine(message);
}
```

As normally, someone using C# for a while you would expect static fields and class constructor (or static constructor) run and initialized before the first instance of a class being created and used. Now this is not entierly true, as we will see it in the following sections.

## .net472 with Debug mode

Running the above application in .net472 with *Debug* mode, the previous statement still looks correct. The output of the application is:

```
Start
LoggerCtr
TestCtr
Working...
Start work
Working2...
Completing work
```

Before the ```Test``` class is being instanciated the ```Logger```'s class ctr runs, because ```Test``` class has a static field typed ```Logger```.

## .net472 with Release mode

Changing to *Release* mode might result the first unexpected behavior. You can instanciate and even invoke a method of a class, and the static field is still not initialized. See how ```Test``` class's ```ctr.```, ```DoWork``` methods both executed before the static field got intialized.

```
Start
TestCtr
Working...
Start work
LoggerCtr
Working2...
Completing work
```

> The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. If a static constructor (Static constructors) 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.
Ref: [Source](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#static-field-initialization)

As there is no static constructor in the ```Test``` class, it is absolutely fine for the runtime to do the *implementation-dependent time prior to the first use* . This has been causing several production bugs and uncomprehending developers, not understanding why everything still looks correct when they debug their application. 

## netcore and Debug or Release mode

Fortunately, .net core fixes this issue of having different behavior in *Debug* and *Release* mode. I am testing with .net core 2.1. Running the same application now results a nearly similar output as the full framework in *Release* mode, though it is still different, resulting a 3rd behavior:

```
Start
TestCtr
Working...
Start work
Working2...
LoggerCtr
Completing work
```

In this configuration not only the ```Test``` class's ```ctr.```, ```DoWork``` but even ```DoWork2``` methods start execution before the static field gets initialized.
Although this seems a subtle difference, it can cause many production bugs and headaches, so it is better keep an eye on static fields. To overcome the behavior we can always add an empty static constructor, so that the static fields get initialized upfront too.

On the plus side, .net core works the same way in *Debug* and *Release* (at least on Windows platform), as well as code can be even step-by-step debugged through.
