5

プロジェクトに静的クラスがもう 1 つある場合、どの静的クラスが最初に初期化されますか?

例: 以下のコードでは、null 例外が発生します。

class Program
    {
        static void Main(string[] args)
        {
            First.Write();
            Second.Write();
        }
    }
    static class First
    {
        public static int[] firstArray = new int[20];
        public static int[] secondArray = Second.secondArray;
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }
    static class Second
    {
        public static int[] firstArray = First.firstArray;
        public static int[] secondArray = new int[30];
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }

注意を払うと、Firstクラスがそれ自体を初期化すると、secondArrayフィールドSecondが null になることがわかります。ただし、Secondクラスが最初に初期化される場合、SecondクラスはfirstArraynull になります。どの初期化が最初に異なる結果になるかを伝えようとしています。

私のプロジェクトに関する抽象的な質問だと思います。予期しない結果が得られる理由を理解しようとしているときに、これに遭遇します。

4

2 に答える 2

10

Firstは初期化を開始し、 を割り当てます。次に、 の初期値を取得するために初期化するfirstArray必要があることに注意してください。SecondsecondArray

Second初期化が開始され、First を初期化する必要があることがわかります。ただし、CLR は、First が現在のスレッドで既に初期化されていることに気付くため、ブロックされません。Secondの初期化が完了し、次に First の初期化が完了します。

幸いなことに、必要なフィールドSecondは既に割り当てられているため、「正しいこと」が起こります。

First 実際に最初に初期化を開始すれば、それで問題ありません。ただし、どちらのクラスにも静的コンストラクターがないため、Secondが最初に初期化を開始する可能性があります。次に、 が初期化を開始しFirstSecondが既に初期化されていることを検出し、Second.secondArrayの現在の値 (null) を取得しますFirst.secondArray。これは悪いことです。.NET 4 では、静的コンストラクターのない型の初期化タイミングが変更されていることに注意してください。これは、仕様を破る方法ではなく、既存のコードを破る方法である可能性があります。

と の両方FirstSecond静的コンストラクターがある場合は、最初に接触Firstするクラスであるため、最初に初期化されます。Main

答えの教訓:これをしないでください。相互に参照する型初期化子は、非常にエラーが発生しやすいものです。別の例として、Eric Lippert と Neal Gafter による NDC 2010 の講演「C# Puzzlers」を参照してください。これは、 NDC ビデオ ページで見ることができます。

于 2010-07-01T11:26:07.953 に答える
0

どの静的型が最初に初期化されるかについての保証はないと思います。この方法でフィールドが適切に初期化されるようにするには、静的コンストラクターを追加する必要があります。

static class Second
{
    public static int[] firstArray = First.firstArray;
    public static int[] secondArray = new int[30];

    static Second() { }

    public static void Write()
    {
        Console.WriteLine(firstArray.ToString());
        Console.WriteLine(secondArray.ToString());
    }
}

さて、同じことをもう一度実行すると、うまくいきます...

于 2010-07-01T11:30:10.130 に答える