4

Consider the following class snippet with two static member variables:

            public static class Foo
            {

                static string A = GetA(B);
                static string B = "required for A";
                ...

Now, my understanding is that A and B will be initialized when they are accessed for the first time. However, when I executed a fully-realized version of the snippet above where A was accessed before B was initialized, it led to null being passed in to GetA() instead of "required for A". Why isn't the behaviour to start initializing A, then, when it's realized that B is required to initialize A, initialize B, then return to finish the initialization of A?

What are the general rules around this? Why does it behave this way? I've seen other questions that touch on this (When do static variables get initialized in C#?) but they don't answer this question exactly. What is the static variable initialization order in C#? talks primarily about how this works across classes, not within a single class (though Jon Skeet's addendum to his answer -- "By popular demand, here was my original answer when I thought the question was about the initialization order of static variables within a class:...." does answer this question, it's buried in a much longer answer).

Adam
  • 8,752
  • 12
  • 54
  • 96
  • @Alexei Levenkov see my edit for why I think this question should be considered separate from the one you linked. Basically, while the answer to my question is buried in John Skeet's answer to the question you linked, the linked question primarily deals with how this works across classes, not within a single class. – Adam Mar 27 '19 at 16:32

1 Answers1

5

In short, don't do this.

Standard ECMA-334 C# Language Specification

15.5.6.2 Static field initialization

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 (§15.5.6.1). Within a partial class, the meaning of "textual order" is specified by §15.5.6.1. If a static constructor (§15.12) 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 fix is to :

  • Put them in the order and use Static Constructor,
  • or just Initialise them in a Static Constructor in turn giving you the ability to control the order of initialisation (given the above information).

Personally i suggest to Initialise them in a Static Constructor, it seems to make it more concrete and understandable, and less likely to be bumped in refactoring

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • OK, I get that in general things are "executed in the textual order in which they appear". But what happens if the initialization of one static field depends on the value of another? Does that change the order of initialization, i.e. the required static field would be initialized first? My example seems to indicate that this isn't the case... – Adam Mar 27 '19 at 16:40
  • In general, I'm still confused. Are static fields initialized in textual order, or does it depend on which fields are accessed first? – Adam Mar 27 '19 at 16:43
  • Looking at your answer and Jon Skeet's answer to the question Alexei Levenkov linked, I think this is the answer: _within_ a class, static members are initialized in textual order. _across_ classes it's a bit more complex, but in a nutshell " If the initializer expression for a static variable requires another type to be initialized, then that other type will be completely initialized before the variable's value is assigned - unless that second type is already being initialized (due to a cyclic dependency)." I believe "types" are a synonym for classes here. – Adam Mar 27 '19 at 17:02
  • @Adam yes Jon's answers is much more precise, however the premise was, sine you have a null problem was to initialise them in a constructor where you have full control over the order. There are no implementation complexities and refactoring will not bump the logic. It also makes it easier to understand what's going on and why. Anyway yes your conclusions seem pretty much correct, good luck – TheGeneral Mar 27 '19 at 21:16