46

私はいくつかの検索を行いましたが、次のコードは出力を生成することが保証されていると思います:

B.X = 7

B.X = 0

A.X = 1

A = 1, B = 0
static class B
{
    public static int X = 7;
    static B() {
        Console.WriteLine("B.X = " + X);
        X = A.X;
        Console.WriteLine("B.X = " + X);
    }
}

static class A
{
    public static int X = B.X + 1;
    static A() {
        Console.WriteLine("A.X = " + X);
    }
}

static class Program
{
    static void Main() {
        Console.WriteLine("A = {0}, B = {1}", A.X, B.X);
    }
}

これを何度も実行しましたが、常にコード セクションの上に出力が表示されます。確認したかったのですが、変更されますか?文章的にも、クラスAとクラスBが再配置されていますか?

静的オブジェクトを最初に使用すると、その静的メンバーの初期化がトリガーされ、続いてその静的コンストラクターがインスタンス化されることが保証されていますか? このプログラムではA.X、 main で を使用すると の初期化がトリガーされ、次にA.Xが初期化され、 の初期化が終了した後、 に進みます。最後に、BX`を出力します。B.XB()A.XA()Main()A.X

4

4 に答える 4

55

ECMA-334 から直接:

17.4.5.1:クラスに静的コンストラクター (§17.11) が存在する場合、静的フィールド初期化子の実行は、その静的コンストラクターを実行する直前に発生します。それ以外の場合、静的フィールド初期化子は、そのクラスの静的フィールドの最初の使用。」

と:

17.11:静的コンストラクターの実行は、アプリケーション ドメイン内で次のイベントの最初の発生によってトリガーされます。

  • クラスのインスタンスが作成されます。
  • クラスの静的メンバーのいずれかが参照されています。

実行が開始される Main メソッド (§10.1) がクラスに含まれている場合、そのクラスの静的コンストラクターは Main メソッドが呼び出される前に実行されます。クラスに初期化子を持つ静的フィールドが含まれている場合、それらの初期化子は、静的コンストラクターを実行する直前にテキスト順に実行されます (§17.4.5)。

したがって、順序は次のとおりです。

  • A.X中古、static A()いわゆる。
  • A.X初期化する必要がありますがB.X、いわゆるを使用しstatic B()ます。
  • B.X初期化する必要があり、7 に初期化されます。B.X = 7
  • のすべての静的フィールドBが初期化されるため、static B()が呼び出されます。Xが印刷された場合 ("7")、 に設定されA.Xます。Aはすでに初期化が開始されているためA.X、デフォルト値である の値を取得します (「クラスが初期化されると、そのクラスのすべての静的フィールドが最初にデフォルト値に初期化されます」); B.X = 0、および印刷されます ("0")。
  • の初期化が完了しB、 の値A.Xが に設定されていB.X+1ます。A.X = 1.
  • のすべての静的フィールドAが初期化されるため、static A()が呼び出されます。A.X("1") が印刷されます。
  • に戻ると、とMainの値が表示されます ("1", "0")。A.XB.X

実際には、標準でこれについてコメントしています。

17.4.5: 変数初期化子を持つ静的フィールドがデフォルト値の状態で観察される可能性があります。ただし、スタイルの問題として、これは強くお勧めできません。

于 2010-09-09T23:20:45.483 に答える
9

この保証には、C# 仕様の約 4 つの異なる規則が関係しており、これは C# に固有のものです。.NET ランタイムによって行われる唯一の保証は、型が使用される前に型の初期化が開始されることです。

  • その静的フィールドは、型初期化子が実行されるまでゼロで初期化されます。
  • その静的フィールド初期化子は、静的コンストラクターの直前に実行されます。
  • その静的コンストラクターは、最初のインスタンス コンストラクター呼び出しまたは最初の静的メンバー参照で呼び出されます。
  • その関数の引数は、左から右の順序で評価されます。

これに依存することは非常に悪い考えです。特に、上記の 4 つの保証のすべてを行わない同様の構文を持つ言語に精通している場合は、コードを読む人を混乱させる可能性があるためです。

Porges のコメントは、観察された動作を保証するには保証が弱すぎるという私の最初の声明 (.NET の動作に基づく) に関連していたことに注意してください。ポージェスは、保証が十分に強力であるという点で正しいですが、実際には、彼が示唆するよりもはるかに複雑な連鎖が関係しています。

于 2010-09-09T22:47:27.263 に答える
-2

静的メンバーの決定論的な初期化は確かに保証されています...しかし、それは「テキストの順序」ではありません。さらに、完全に怠惰な方法で実行されるとは限りません (つまり、静的変数が最初に参照されたときのみ)。ただし、整数を使用した例では、違いはありません。

場合によっては、遅延初期化を取得することが望ましい場合があります (特に高価なシングルトンを使用する場合)

于 2010-09-09T22:40:54.163 に答える