While working on a C# app I just noticed that in several places static initializers have dependencies on each other like this:
static private List<int> a = new List<int>() { 0 };
static private List<int> b = new List<int>() { a[0] };
Without doing anything special that worked. Is that just luck? Does C# have rules to resolve this?
Edit: (re: Panos) In a file lexical order seems to be king? what about across files?
In looking I tried a cyclical dependency like this:
static private List<int> a = new List<int>() { b[0] };
static private List<int> b = new List<int>() { a[0] };
and the program didn't run the same (the test suit failed across the board and I didn't look further).
See section 10.4 of the C# spec for the rules here:
So in other words, in your example 'b' is initialized to its default state (null) and so the reference to it in the initializer of 'a' is legal but would result in a NullReferenceException.
These rules are different to Java's (see section 8.3.2.3 of the JLS for Java's rules about forward references, which are more restrictive).
It seems to depend on the sequence of lines. This code works:
while this code does not work (it throws a
NullReferenceException
)So, obviously no rules for cyclical dependency exist. It's peculiar however that the compiler does not complain...
EDIT - What's happening "across files"? If we declare these two classes:
and try to access them with this code:
we are getting this output:
So the initialization of
B
causes an exception in static constructorA
and lefts fielda
with the default value (null). Sincea
isnull
,b
can not also be initialized properly.If we do not have cyclical dependencies, everything works fine.
EDIT: Just in case you didn't read the comments, Jon Skeet provides a very interesting reading: The differences between static constructors and type initializers.
Personally I would get rid of the static initializers since it isn't clear and add a static constructor to initialize these variables.
Then you don't have to guess what is going on and you're being clear in your intentions.
Yes, you were lucky. C# appears to execute the code in the order it appears in the class.
Will work but ...
Will fail.
I would recommend putting all your dependencies in one place, the static constructor is the place for this.