Below are two different ways to initialize static readonly fields. Is there a difference between the two approaches? If yes, when should one be preferred over the other?
class A { private static readonly string connectionString = WebConfigurationManager.ConnectionStrings["SomeConnection"].ConnectionString; } class B { private static readonly string connectionString; static B() { connectionString = WebConfigurationManager.ConnectionStrings["SomeConnection"].ConnectionString; } }
Constant and ReadOnly keyword is used to make a field constant which value cannot be modified. The static keyword is used to make members static that can be shared by all the class objects.
Static constructor will be called first time when the class is referenced. Static constructor is used to initialize static members of the class. In the non static class the private or public constructor will not be called. Static members will not be initialized either by private or public constructor.
You can initialize a ReadOnly property in the constructor or during object construction, but not after the object is constructed.
A static constructor is called automatically. It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs before an instance constructor.
There is one subtle difference between these two, which can be seen in the IL code - putting an explicit static constructor tells the C# compiler not to mark the type as beforefieldinit. The beforefieldinit affects when the type initializer is run and knowing about this is useful when writing lazy singletons in C#, for example.
In brief the difference is this:
.class private auto ansi beforefieldinit A .class private auto ansi B
In all other aspects they are the same. Output from Reflector:
Class A:
.class private auto ansi beforefieldinit A extends [mscorlib]System.Object { .method private hidebysig specialname rtspecialname static void .cctor() cil managed { .maxstack 8 L_0000: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings L_0005: ldstr "SomeConnection" L_000a: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0) L_000f: ldfld string Connection::ConnectionString L_0014: stsfld string A::connectionString L_0019: ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .field private static initonly string connectionString }
Class B:
.class private auto ansi B extends [mscorlib]System.Object { .method private hidebysig specialname rtspecialname static void .cctor() cil managed { .maxstack 8 L_0000: nop L_0001: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings L_0006: ldstr "SomeConnection" L_000b: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0) L_0010: ldfld string Connection::ConnectionString L_0015: stsfld string B::connectionString L_001a: ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .field private static initonly string connectionString }
The beforefieldinit attribute indicates how the initialization happens.
In case of an explicit static constructor initialization, the initialization of the static member happens the moment the type is accessed. In the example given in case of class A, the initialization will happen only when connectionString is first referred, whereas in case of class B initialization will happen the first time the type class B is referred, not necessarily accessing connectionString.
Only C# (.NET 4.0 ) provides us control over how static members can be initialized. With VB.NET only the non beforefieldinit method is possible whereas with C++/CLI only the beforefieldinit mechanism is possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With