Ниже два различных способа инициализировать статические поля только для чтения. Существует ли различие между двумя подходами? Если да, когда нужно быть предпочтен по другому?
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;
}
}
Есть одно тонкое различие между этими двумя, которое можно увидеть в коде IL - добавление явного статического конструктора сообщает компилятору C # не отмечать тип как beforefieldinit . Параметр beforefieldinit влияет на запуск инициализатора типа, и знание этого полезно, например, при написании ленивых синглтонов на C # .
Вкратце разница заключается в следующем:
.class private auto ansi beforefieldinit A
.class private auto ansi B
Во всех других аспектах они одинаковы. Вывод отражателя:
Класс 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
}
Класс 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
}
По сути, они одинаковы, но если у вас есть и назначение только для чтения статическому полю и конструктор статического типа, сначала выполняется присвоение только для чтения.