2010-05-03 5 views

Répondre

31

Il existe une différence subtile entre ces deux, qui peut être vu dans le code IL - mettre un constructeur statique explicite dit au compilateur C# de ne pas marquer le type beforefieldinit. Le beforefieldinit affecte quand l'initialiseur de type est exécuté et savoir à ce sujet est utile lors de l'écriture lazy singletons in C#, par exemple.

En bref la différence est la suivante:

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

Dans tous les autres aspects, ils sont les mêmes. Sortie du réflecteur:

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

Ils sont essentiellement les mêmes, mais si vous arrive d'avoir à la fois une affectation en lecture seule à un champ statique et un constructeur de type statique, l'affectation de lecture seule se produit d'abord.

13

Le beforefieldinit attribut indique comment l'initialisation se produit.

Dans le cas d'une initialisation de constructeur statique explicite, l'initialisation du membre statique se produit au moment où le type est accédé. Dans l'exemple donné en cas de classe A, l'initialisation se fera uniquement lorsque connectionString est référencée en premier, alors qu'en cas d'initialisation de classe B, la première classe de type B sera référencée, sans nécessairement accéder à connectionString. Seul C# (.NET 4.0) nous permet de contrôler la façon dont les membres statiques peuvent être initialisés.

Avec VB.NET seule la méthode non beforefieldinit est possible alors qu'avec C++/CLI seul le mécanisme beforefieldinit est possible.

Questions connexes