I'm gradually moving all my C# articles to the web site for my book, C# in Depth. This article has already moved. I'm leaving the content here so that existing links still work, but I won't be updating this page.
Please visit the new location for this article.
beforefieldinit
Some implementations of the singleton pattern rely on the behaviour of static constructors and type initializers, in particular with respect to the time at which they are invoked.
The C# specification (ECMA 334) states in section 17.11:
The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:
|
The CLI specification (ECMA 335) states in section 8.9.5:
|
The C# specification implies that no types
with static constructors should be marked with the beforefieldinit
flag.
Indeed, this is upheld by the compiler, but with a slightly odd effect. I suspect
many programmers believe (as I did for a long time) that the following classes were
semantically equivalent:
class Test { static object o = new object(); } class Test { static object o; static Test() { o = new object(); } } |
The two classes are not, in fact, the same. They both have type initializers - and the
two type initializers are the same. However, the first does not have a static constructor,
whereas the second does. This means that the first class can be marked as beforefieldinit
and have its type initializer invoked at any time before the first reference to a static field
in it. The static constructor doesn't even have to do anything. This third class is
equivalent to the second:
class Test { static object o = new object(); static Test() { } } |
I believe this is a source of significant confusion - particularly in terms of singleton implementations.
beforefieldinit
- lazy or not?
The beforefieldinit
flag has a strange effect, in that it can
not only mean that a type initializer is invoked earlier than
that of an equivalent type without the flag - it could even be invoked
later, or not at all. Consider the following program:
using System; class Driver { public static void Main() { Console.WriteLine ("Starting Main"); // Invoke a static method on Test Test.EchoAndReturn ("Echo!"); Console.WriteLine ("After echo"); // Reference a static member of Test string y = Test.x; // Use the value just to avoid compiler cleverness if (y != null) Console.WriteLine ("After field access"); } } class Test { public static string x = EchoAndReturn ("In type initializer"); public static string EchoAndReturn (string s) { Console.WriteLine (s); return s; } } |
The results of running the above are quite varied. The runtime could decide to run the type initializer on loading the assembly to start with:
In type initializer Starting Main Echo! After echo After field access |
Or perhaps it will run it when the static method is first run...
Starting Main In type initializer Echo! After echo After field access |
Or even wait until the field is first accessed...
Starting Main Echo! After echo In type initializer After field access |
(In theory, the type initializer could even be run after "Echo!" is displayed, but before
"After echo" is displayed. I would be very surprised to see any runtime actually show this
behaviour, however.) With a static constructor in Test
, only the middle of
these is possible. So, beforefieldinit
can make the invocation of the type
initializer even lazier (the last result) or more eager (the first result). I suspect
even those developers who know of the existence of beforefieldinit
may be
surprised by this. The MSDN documentation for TypeAttributes.BeforeFieldInit
is particularly poor in this respect. It describes the flag like this:
Specifies that calling static methods of the type does not force the system to initialize the type. |
While this is true in the strictest possible sense, it certainly isn't the complete story - it suggests that the flag only makes the initialization lazier, not more eager.
I propose the following changes:
beforefieldinit
. (Modification to the
C# language specification.)
The above changes are all entirely backwards-compatible, and require no CLI modification.
The first of the above proposals is definitely the most controversial. (The last isn't controversial at all, as far as I can see.) The reason is performance. Not many classes actually need the behaviour assumed by many C# programmers - most people need never know the difference, really. The JIT compiler, however, cares quite a lot: if a static member is used within a fairly tight loop, for instance, it makes a lot of sense to initialise the type before entering the loop, knowing thereafter that the type has already been initialised. When code is shared between app domains etc, I gather this becomes even more important. Making the performance of existing code decrease by recompilation with a new version of the framework would undoubtedly be unpopular. I'm therefore willing to concede as a less-than-ideal proposal - indeed I've only left it in this page for historical reasons (I dislike the idea of being a revisionist). The second proposal, however, is still important - both to allow classes which do have a static constructor to improve their performance with BeforeFieldInit semantics if appropriate, and to allow classes which currently only need a static constructor to get rid of BeforeFieldInit semantics to achieve this aim in a more self-documenting manner. (A junior developer is more likely to remove a static constructor which appears to be a no-op than to remove an attribute they don't fully understand.)
Back to the main page.