static field variable initializer FAILS in online compiler but works in VS

80 Views Asked by At

I would like to get some clarification in regards to how loose the execution timing is for static field initializers in .NET. I'm getting a TypeInitializationException when running the code below in an online compiler(Fiddle), but I get the expected output of 1 in a test console app in VS.

Code:

using System;
using SimpleInjector;   

public class Program
{
    public static IFactory Factory { get; set; }
        
    public interface IFactory { T GetInstance<T>() where T: class; }
    
    public class SimpleFactory: IFactory
    {
        private readonly Container _container;
        public SimpleFactory(Container container) { this._container = container; }
        public T GetInstance<T>() where T : class { return _container.GetInstance<T>(); }
    }
    
    public class Bar { public int Get() { return 1; } }

    public static class Foo
    {
        //static Foo() {}
        public static readonly int foo = Factory.GetInstance<Bar>().Get();
    }
        
    public static void Main()
    {
        var container = new Container();
        var factory = new SimpleFactory(container);
        
        container.RegisterInstance(Factory = factory);
        container.Register<Bar>();
                
        Console.WriteLine(Foo.foo);
    }
}

Stack trace from online compilation:

[System.NullReferenceException: Object reference not set to an instance of an object.]
   at Program.Foo..cctor() :line 22

[System.TypeInitializationException: The type initializer for 'Foo' threw an exception.]
   at Program.Main() :line 33

What gives? Is it safe to assume that when building under visual studio the code is always guaranteed to work correctly? Thank you for your time.

1

There are 1 best solutions below

0
On BEST ANSWER

According to the C# language spec, this is specifically pointed out as an implementation-dependent thing:

If a static constructor 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.

The only guarantee you get, is that it must be some time before the first use of a static field.

However, as you probably have found out in your fiddle, adding a static constructor makes this work. A static constructor guarantees that static field initialisers to be run immediately before the static constructor. The good news is that the execution of the static constructor is not implementation-dependent (spec):

The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • An instance of the class type is created.
  • Any of the static members of the class type are referenced.