статический инициализатор поля только для чтения и статическая инициализация конструктора - PullRequest
35 голосов
/ 04 мая 2010

Ниже приведены два разных способа инициализации статических полей только для чтения. Есть ли разница между двумя подходами? Если да, то когда один должен быть предпочтительнее другого?

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;
    }
}

Ответы [ 4 ]

33 голосов
/ 04 мая 2010

Существует одно тонкое различие между этими двумя, которое можно увидеть в коде 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    
}
15 голосов
/ 17 марта 2012

Атрибут beforefieldinit указывает, как происходит инициализация.

В случае явной статической инициализации конструктора, инициализация статического члена происходит в момент обращения к типу. В примере, приведенном в случае класса A, инициализация будет происходить только при первом обращении к connectionString , тогда как в случае инициализации класса B произойдет при первом обращении к классу типа B, не обязательно получая доступ 1007 * ConnectionString .

Только C # (.NET 4.0) предоставляет нам контроль над тем, как статические члены могут быть инициализированы. В VB.NET возможен только метод non beforefieldinit , тогда как в C ++ / CLI возможен только механизм beforefieldinit .

7 голосов
/ 04 мая 2010

Они, по сути, одинаковы, но если у вас есть оба статические поля, предназначенные только для чтения, и конструктор статических типов, сначала доступно только чтение. .

0 голосов
/ 05 марта 2019

Я должен добавить, что при наличии явного конструктора (не версии beforefieldinit) доступ к статическим элементам сравнительно медленнее.

...