inizializzazione del campo di sola lettura statica rispetto all'inizializzazione del costruttore statico

inizializzazione del campo di sola lettura statica rispetto all'inizializzazione del costruttore statico

C'è una sottile differenza tra questi due, che può essere vista nel codice IL:l'inserimento di un costruttore statico esplicito indica al compilatore C# di non contrassegnare il tipo come beforefieldinit. Il beforefieldinit ha effetto quando viene eseguito l'inizializzatore del tipo e conoscerlo è utile quando si scrivono singleton pigri in C#, ad esempio.

In breve la differenza è questa:

.class private auto ansi beforefieldinit A
.class private auto ansi B

In tutti gli altri aspetti sono uguali. Uscita dal riflettore:

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

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

Il primafieldinit attributo indica come avviene l'inizializzazione.

In caso di un'inizializzazione esplicita del costruttore statico, l'inizializzazione del membro statico avviene nel momento in cui si accede al tipo. Nell'esempio fornito in caso di classe A, l'inizializzazione avverrà solo quando connectionString viene prima riferito, mentre nel caso di classe B l'inizializzazione avverrà la prima volta che viene riferito il tipo classe B, non necessariamente accedendo a connectionString .

Solo C# (.NET 4.0 ) ci fornisce il controllo su come inizializzare i membri statici. Con VB.NET solo il non beforefieldinit è possibile mentre con C++/CLI solo beforefieldinit meccanismo è possibile.


Sono essenzialmente gli stessi, ma se ti capita di avere entrambi un'assegnazione di sola lettura a un campo statico e un costruttore di tipo statico, viene eseguita prima l'assegnazione di sola lettura.