Today I wrote a simple application, which shows what the difference is
between initializing a static field in the explicit static constructor
and doing the same during the declaration time (inline). I know that
even when we initialize our static fields inline, the compiler will add
an implicit static constructor to that class and initialize static
values in that method. But this example showed me that there is really a
long time difference between initializing static fields inline and in
explicit static constructor. Here are a screenshot from the example - in
this example BeforeFieldInit means that the static fields are
initialized inline and NotBeforeFieldInit means that static fields are
initialized in the explicit static constructor:
Download Example Code
Declaring a static field and initializing its value in an explicit
static constructor.
|
using System;
namespace
BeforeFieldInitExample
{
public class NotBeforeFieldInit
{
// here there is only decleration of the static field
public
static int A;
static NotBeforeFieldInit()
{
// Initialization of A's values is here in the
explicit static constructor
A = 0;
}
}
}
|
Initializing a static fields value during the decleration (inline).
|
using System;
namespace BeforeFieldInitExample
{
public class BeforeFieldInit
{
public
static int A = 0;
}
}
|
These two code groups will work as the same and produce the same result.
Actually when we compile the second code, the output will be as the
same with the first code. I mean, during the compiling time the compiler
will create an implicit static constructor for the BeforeFieldInit
class and initialize the field's value in that method. So it will be the
same with the first code.
But there is a small difference between these codes. The difference can
only be seen by checking the IL codes of these types.
For the first example, IL code of the class NotBeforeFieldInit will be
as follows:
|
.class public auto ansi NotBeforeFieldInitClass
extends object
{
.method public hidebysig specialname
rtspecialname instance
void .ctor() cil managed
{
// Code Size: 7 byte(s)
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void object::.ctor()
L_0006: ret
}
.method private hidebysig specialname
rtspecialname static
void .cctor() cil managed
{
// Code Size: 22 byte(s)
.maxstack 8
L_0000: nop
L_0001: ldc.i4.0
L_0002: stsfld int32
BeforeFieldInitExample.NotBeforeFieldInitClass::A
L_0007: ldc.r8 9
L_0010: stsfld float64
BeforeFieldInitExample.NotBeforeFieldInitClass::B
L_0015: ret
}
.field public static int32 A
.field
public static float64 B
}
|
And for the second example, which the name of the class is
BeforeFieldInit's IL code will be as runs:
.class public auto ansi
beforefieldinit // here beforefieldinit mask is added
BeforeFieldInitClass
extends object
{
.method public hidebysig specialname
rtspecialname instance
void .ctor() cil managed
{
// Code Size: 7 byte(s)
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void object::.ctor()
L_0006: ret
}
.method private hidebysig specialname
rtspecialname static
void .cctor() cil managed
{
// Code Size: 21 byte(s)
.maxstack 8
L_0000: ldc.i4.0
L_0001: stsfld int32
BeforeFieldInitExample.BeforeFieldInitClass::A
L_0006: ldc.r8 9
L_000f: stsfld float64
BeforeFieldInitExample.BeforeFieldInitClass::B
L_0014: ret
}
.field public static int32 A
.field
public static float64 B
}
|
IL codes generated by Xenocode Fox 2007
As you see in the IL the only difference between these two codes is the
second class's having the
beforefieldinit flag. So what
is this flag doing?
beforefieldinit flag tells to the JIT that this class's
static fields are initialized inline. If a class has no
beforefieldinit
flag, then JIT compiler will automatically check whether explicit
static constructor is called before. This means that whenever you want
to try to access any static member of this class or try to create a new
instance of this class, JIT will automatically calls the explicit static
constructor. Therefore you will loose performance because whenever you
try to access a static member, JIT also checks whether static
constructor is invoked before. But in the second example if we add a
beforefieldinit
flag to our class, this means that our static members are initialized
inline, so JIT does not need to check whether static constructor is
invoked before. This is the main reason that causes performance
difference between those two classes. When we wrote an explicit static
constructor and initialize our fields' values, the compiler will not add
beforefieldinit flag to that class. But if we
initialize our static fields inline, then compiler will add an implicit
static constructor and initialize our static fields there and also add
the
beforefieldinit flag to our class.
So always, try to use inline field initialization for the
static fields if you can.