This is one of the stranger bugs I’ve come across lately. I have a static class, and that static class has a static constructor. I’ve provided an extremely pared down example here to demonstrate:
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public static class Test
{
private static readonly List<string> _testList;
static Test()
{
_testList = new List<string>();
Debug.Log(_testList.Count);
_testList.Add("Hello");
_testList.Add("World");
}
}
If I just run the game or recompile my code, the debug log shows 0 as expected, but if I put a breakpoint on the Debug.Log line and inspect _testList I see that it is already initialized with 2 values. Then when I resume the program there will be be two or more logs in the console, and occasionally some of them will log 2 instead of 0. My working theory is it has something to do with how the debugger works, and mousing over values to preview them actually invokes the static constructor from within itself recursively? If that’s what’s happening then I can probably safely ignore this issue, but if that’s not it I’d love to understand what’s really going on.
Can’t this be related to [InitializeOnLoad]? I don’t know how static constructors are called by Unity with this attribute. Normally they are called when type is used first time, but this can’t be done like that via reflection I guess. That’s why it can be called first time by Unity via reflection and second time by debugger after normal type usage. I would simply create _isInitialized and check it for situations where Test is used by other code.
I don’t have “Enter Play Mode Options” enabled at all, which I think means the domain should be reloading. Even so, I’d be surprised if that resulted in the Constructor being called multiple times, if anything it would be called less often no?
Good thought, but I don’t think it’s related. I’m not using the attribute in my real example, it was just easier for the little demo I threw together. (In my real use case it’s a utility class being accessed by a PropertyDrawer if that matters).
Static constructors executed as many times as domain reloads, but I don’t think this problem is related to the static constructor. If it was, you would just generate another pack of garbage with the new List<> and would always have zero in the Log unless you or Unity runs tests parallel (async or whatever). My guess is you somewhere have race condition. Also I think it is always a good idea to put some identification in the Log so you make sure you are looking at the same lines where the log data comes from.