3

I'm getting a TypeInitializationException when running this C# code.
It happens when a constructor tries to add an instance to a static list that should already be initialized.

You can run it here:
https://www.programiz.com/online-compiler/7Z2b1vggBclrq

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello");
        Base baseClass = Base.getElement("test1");
    }
}

public class Derived : Base
{
    public static Derived derived_1 = new Derived("test1");
    public static Derived derived_2 = new Derived("test2");
    public static Derived derived_3 = new Derived("test3");
    public static Derived derived_4 = new Derived("test4");

    protected Derived(string field1) : base(field1)
    {
    }
}

public class Base
{
    public static List<Base> list;
    public static Base[] derivedClass;

    static Base()
    {
        list = new List<Base>();
        derivedClass = new Base[]
        {
            Derived.derived_1,
            Derived.derived_2,
            Derived.derived_3,
            Derived.derived_4
        };
    }

    public string field1;

    protected Base(string field1)
    {
        this.field1 = field1;
        list.Add(this); // list is null here
    }

    public static Base getElement(string field1)
    {
        foreach (var element in list)
        {
            if (element.field1.Equals(field1))
            {
                return element;
            }
        }
        return null;
    }
}

Output

ERROR!

Unhandled Exception:
System.TypeInitializationException: The type initializer for 'Base' threw an exception. ---> System.TypeInitializationException: The type initializer for 'Derived' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object
  at Base..ctor (System.String field1) [0x0000f] in <db66da3dae244ddc8dabed6518753b54>:0 
  at Derived..ctor (System.String field1) [0x00000] in <db66da3dae244ddc8dabed6518753b54>:0 
  at Derived..cctor () [0x00000] in <db66da3dae244ddc8dabed6518753b54>:0 
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
  at Program.Main () [0x0000c] in <db66da3dae244ddc8dabed6518753b54>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'Base' threw an exception. ---> System.TypeInitializationException: The type initializer for 'Derived' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object
  at Base..ctor (System.String field1) [0x0000f] in <db66da3dae244ddc8dabed6518753b54>:0 
  at Derived..ctor (System.String field1) [0x00000] in <db66da3dae244ddc8dabed6518753b54>:0 
  at Derived..cctor () [0x00000] in <db66da3dae244ddc8dabed6518753b54>:0 
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
  at Program.Main () [0x0000c] in <db66da3dae244ddc8dabed6518753b54>:0 

The confusing part is that the static fields (list and derivedClass) are clearly initialized in the static constructor, yet when list.Add(this) runs inside the base constructor, list is still null.

For context: this same pattern works in Java, but in C# it throws during static initialization.

Question: Why does this throw a TypeInitializationException even though the static fields are initialized?

12
  • 3
    Besides, whatever you're trying to do, you don't need such code. What are you trying to do? And why use public fields at all? This is a major bug. Fields, even public ones, are just implementation details. Properties aren't just get/set methods, only they are are part of a type's programming surface. Commented Nov 3 at 13:04
  • 1
    I cannot reproduce this on .NET 9. I don't get any exceptions. The link to the online compiler seems to be broken. Commented Nov 3 at 13:06
  • I can reproduce this in dotnetfiddle.net but only for .NET Framework versions. .NET Core (which includes .NET 5 and later) work fine. Now I'll have to go read the specs again, to see when this was resolved Commented Nov 3 at 13:09
  • 7
    There's unspecified behavior involved here, in terms of when the Derived type initializer is executed, because there's no static constructor. See codeblog.jonskeet.uk/2010/01/26/… for an example of how this has changed over time. Fundamentally: don't do this sort of thing, it's too hard to reason about and get right. (If you must do something like this, use static constructors to make the timing easier to reason about.) Commented Nov 3 at 14:07
  • 1
    It looks like an attempt of implementing enum-like class. Here is the fixed version for 4.7 (override ToString if you want to see "field1" as output). Commented Nov 3 at 14:35

1 Answer 1

0

I added some Console.WriteLine statements to understand the exact execution flow of your code. I found that the exception occurs mainly due to the difference in the runtime being used for execution. When this code is executed on the .NET 8 runtime, it doesn’t throw any exceptions and works as expected.

However, the online IDE (www.programiz.com) you’re using runs on Mono 6.12.0.182, and that’s where the issue arises.

Here’s what happens:

  • When executed in Visual Studio (.NET 8 runtime), the static constructor of the base class is called first. This initializes the list before the non-static constructor is called, so everything works fine.

  • But when executed in the online IDE (Mono 6.12.0.182 runtime), the non-static constructor of the base class is called first. That’s why it throws a TypeInitializationException — the non-static constructor tries to insert an object into a list that hasn’t been initialized yet.

In short, the entire difference comes down to the underlying runtime behavior.

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.