18

なぜこのコードは無限の再帰に終わらないのだろうか。静的メンバーのデフォルト値への自動初期化に関連していると思いますが、誰かが「ステップバイステップ」で「a」が2の値を取得し、「b」が1の値を取得する方法を教えてもらえますか?

public class A
{
    public static int a = B.b + 1;
}
public class B
{
    public static int b = A.a + 1;
}

static void Main(string[] args)
{
    Console.WriteLine("A.a={0}, B.b={1}", A.a, B.b); //A.a=2, B.b=1
    Console.Read();
}
4

6 に答える 6

16

私は推測します:

  • A.aクエリが実行され、A静的初期化子が起動します
  • これはにアクセスB.bし、B静的初期化子を起動させます
  • A.a照会されます。タイプ初期化子はすでにアクティブ化されているため(ただし、割り当てはまだ行われていません)、フィールド(まだ割り当てられていない)は次のように読み取られます。0
  • 0+1は、 <===========================1に割り当てられますB.b
  • cctorを終了し、cctorBに戻ります。A
  • 1+1は、 <===========================2に割り当てられますA.a
  • Acctorを終了します
  • 2が返さWriteLineれます()A.a
  • クエリ(on WriteLineB.b; cctorはすでに解雇されているので、1
于 2010-05-06T21:20:59.843 に答える
12

マークは正しいです。私は彼の答えに、あなたの質問は仕様のセクション10.5.5.1によって答えられていると付け加えます。

クラスの静的フィールド変数初期化子は、クラス宣言に表示されるテキストの順序で実行される一連の割り当てに対応します。静的コンストラクターがクラスに存在する場合、静的フィールド初期化子の実行は、その静的コンストラクターを実行する直前に行われます。それ以外の場合、静的フィールド初期化子は、そのクラスの静的フィールドを最初に使用する前に、実装に依存する時間に実行されます。

最後のポイントに注意してください。仕様では、いずれかの注文が仕様で許可されている場合として、正確な例を引用しています。すべての仕様保証は、静的コンストラクターが実行される前に、フィールド初期化子がテキスト順に実行されることです。あるタイプのフィールドが別のタイプのフィールドの前または後に初期化されることを保証するものではありません。

たとえば、jitコンパイラは、「このメソッドでタイプAとBが初めて使用され、これらのタイプがロードされていることを確認します」と言うことが許可されています。この時点で、ジッタはフィールド初期化子の実行を許可されており、その裁量でAを最初に実行するかBを最初に実行するかを選択できます。

つまり、(1)この動作に依存することはできません。それは実装定義であり、(2)仕様はあなたの正確な質問に答えます。言語のセマンティクスについて質問がある場合は、仕様を読むことを検討してください

于 2010-05-06T22:11:05.157 に答える
6

これは、静的プロパティにアクセスする順序と関係があります。最初に評価されるのはAaです。Aaを評価するとき、Bbは初期化されます。aへの実際の割り当てが終了していないため、aの値は0のままであり、Bbは1になります。Bbが初期化された後、値をAa、つまり1 + 1、つまり2に割り当てることができます。

于 2010-05-06T21:20:07.770 に答える
2

ロードする最初のタイプはたまたまAです。したがって、型がロードされ、その静的メンバーaはデフォルト値のゼロを取得します。その後、Aの静的コンストラクターが呼び出されます。そのコンストラクターは型Bを参照するため、Bロードされ、静的コンストラクターが呼び出されます。そのコンストラクターは、タイプを参照しますAが、Aすでにロードされているため、ここでは何も起こらずb、ゼロの値(現在の値a)に1を加えた値を取得します。その後、静的コンストラクターがB戻り、aの値が計算されます。

于 2010-05-06T21:21:56.860 に答える
2

興味深いことに、サンプルコードの出力順序を変更したとき:

    Console.WriteLine("B.b={0} A.a={1}", B.b, A.a);

私は反対の結果を得ました:

B.b=2 A.a=1

つまり、アクセスされる順序に関係しているように見えます

したがって、変数の1つを早期に使用することで出力が変わる可能性があることを考えると、そのような再帰的に定義された値はA BAD IDEA(TM)のようです:-)

于 2010-05-06T21:24:05.657 に答える
1

Console.WriteLineではAaが最初に参照されるため、最初にロードされます。これにより、BはAaの値を0 => Bb = 1=>Aaとしてロードされます。

印刷を逆にして、それが逆に起こるのを見てください。

于 2010-05-06T21:27:20.563 に答える