sta*_*ser 38 c# static-constructor initializer c#-3.0 c#-2.0
以下是初始化静态只读字段的两种不同方法.两种方法之间有区别吗?如果是的话,什么时候应该优先于另一个呢?
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;
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ers 36
这两者之间有一个细微的区别,可以在IL代码中看到 - 将显式静态构造函数告知C#编译器不要将类型标记为beforefieldinit.beforefieldinit影响何时运行类型初始化程序,例如,在C#中编写惰性单例时,了解这一点很有用.
简而言之,区别在于:
.class private auto ansi beforefieldinit A
.class private auto ansi B
Run Code Online (Sandbox Code Playgroud)
在所有其他方面,它们是相同的.反射器的输出:
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
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
Swa*_* PR 15
该beforefieldinit属性表示初始化是如何发生的.
在显式静态构造函数初始化的情况下,静态成员的初始化在访问类型时发生.在类A的情况下给出的示例中,初始化将仅在首次引用connectionString时发生,而在类B的情况下,初始化将在第一次引用类型类B时发生,而不一定访问connectionString.
只有C#(.NET 4.0)使我们能够控制如何初始化静态成员.使用VB.NET只能使用非beforefieldinit方法,而使用C++/CLI时,只能使用beforefieldinit机制.