Few weeks ago, I switched from Java to C#. Today, I had a weird behavior and I try to reproduce it in this simple sample. I’m using a .net FW 4.
I have three classes:
First, the abstract one:
namespace ReadonlyStaticOrder
{
using System;
using System.Collections.Generic;
public abstract class AbstractClass
{
public AbstractClass(string value, IEnumerable<string> someValues)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (someValues == null)
{
throw new ArgumentNullException("someValues");
}
// would do something after...
}
}
}
The second one :
namespace ReadonlyStaticOrder
{
using System.Collections.Generic;
public sealed class ReadonlyOrderInitialization : AbstractClass
{
// this line introduces the bug, since it call the ctor before SomeValues already initialized
// if removed, no more exception
public static readonly ReadonlyOrderInitialization Sample = new ReadonlyOrderInitialization("sample");
private static readonly IEnumerable<string> SomeValues = new string[] { "one", "two", "three" };
public ReadonlyOrderInitialization(string value)
: base(value, SomeValues)
{
}
}
}
And the demonstrator:
namespace ReadonlyStaticOrder
{
using System;
public sealed class Program
{
static void Main(string[] args)
{
try
{
new ReadonlyOrderInitialization("test");
}
catch (TypeInitializationException typeInitializationException)
{
Console.WriteLine(typeInitializationException.Message);
Console.WriteLine(typeInitializationException.InnerException.Message);
Console.WriteLine(typeInitializationException.StackTrace);
}
Console.ReadLine();
}
}
}
And the output is:
The type initializer for
‘ReadonlyStaticOrder.ReadonlyOrderInitialization’ threw an exception.
Value cannot be null. Parameter name: someValues at
ReadonlyStaticOrder.ReadonlyOrderInitialization..ctor(String value)
at ReadonlyStaticOrder.Program.Main(String[] args) in
d:\stackoverflow\static
readonlyissue\ConsoleApplication1\ReadonlyStaticOrder\Program.cs:line
12
I added a comment on the line which introduces the bug. For me, the compiler would have to warn me that the behavior can be weird because of the order of static initialization. Am I wrong?
Thank you guys and I hope you have enough information.
It is defined as text order – §17.11 in ECMA 334:
As an aside, this gets particularly interesting if you consider
partial classes, in which case : it is not defined.If in doubt, move the initialization explicitly to a static constructor.
As for why; consider (note: these are just my own thoughts):
partial classesissue, the full order itself is not strictly defined; so it cannot handle the general case – and again, covering a specific case (single class fragment etc) is back to the “thin veneer” (where it only warns for the obvious cases, but can’t help with the non-trivial ones)