2010-05-03 6 views

ответ

31

Существует одно тонкое различие между этими двумя, которое можно увидеть в коде IL - помещение явного статического конструктора сообщает компилятору C# не отмечать тип как beforefieldinit. Функция beforefieldinit влияет, когда запускается инициализатор типа, и знать об этом полезно, например, при написании lazy singletons in 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  
} 
5

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

13

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

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

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