47

以下は、静的読み取り専用フィールドを初期化する 2 つの異なる方法です。2つのアプローチに違いはありますか?はいの場合、いつ一方を他方よりも優先する必要がありますか?

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

4 に答える 4

40

これら2つの間に微妙な違いが1つあります。これは、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    
}
于 2010-05-03T21:46:45.153 に答える
18

beforefieldinit属性は、初期化がどのように行われるかを示します。

明示的な静的コンストラクターの初期化の場合、型がアクセスされた瞬間に静的メンバーの初期化が行われます。クラス A の場合の例では、 connectionStringが最初に参照されたときにのみ初期化が行われますが、クラス B の場合、型クラス B が最初に参照されたときに初期化が行われ、必ずしもconnectionStringにアクセスする必要はありません。

静的メンバーの初期化方法を制御できるのは、C# (.NET 4.0) だけです。VB.NET では非 beforefieldinitメソッドのみが可能ですが、C++/CLI ではbeforefieldinitメカニズムのみが可能です。

于 2012-03-16T20:07:30.087 に答える
7

これらは本質的に同じですが、静的フィールドへの読み取り専用割り当て静的型コンストラクターの両方がある場合は、読み取り専用割り当てが最初に発生します。

于 2010-05-03T21:41:15.447 に答える