2009-04-02 8 views
18

コンストラクタが呼び出される前に静的フィールドの初期化を完了する必要がありますか?静的フィールドの初期化はどのようにC#で動作するのですか?

次のプログラムは、私に間違っていると思われる出力を提供します。

new A() 
_A == null 
static A() 
new A() 
_A == A 

コード:

public class A 
{ 
    public static string _A = (new A()).I(); 

    public A() 
    { 
     Console.WriteLine("new A()"); 
     if (_A == null) 
      Console.WriteLine("_A == null"); 
     else 
      Console.WriteLine("_A == " + _A); 
    } 

    static A() 
    { 
     Console.WriteLine("static A()"); 
    } 

    public string I() 
    { 
     return "A"; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var a = new A(); 
    } 
} 

答えて

22

これは正しいです。

静的な初期化子は、標準のコンストラクタの前で実行されますが、実行時には新しいA()を使用しており、静的でないコンストラクタのパスを通過します。これにより、表示されるメッセージが表示されます。ここで

は、実行のフルパスです:あなたが最初のプログラムでvar a = new A();を呼び出すと、これはAがアクセスされた最初の時間

です。

これは、この時点でA._A

の静的初期化をオフに起動します、A._Aは_A = (new A()).I();

を構築し、この時点で、_Aがされていないので、これは


Console.WriteLine("new A()"); 
if (_A == null) 
    Console.WriteLine("_A == null");   

を打ちます返され、構築された型(まだ)で設定されます。

次に、静的コンストラクタA { static A(); }が実行されます。これは "静的なA()"メッセージを表示します。

最後に、元のステートメント(var a = new A();)が実行されますが、この時点で統計が構築されるため、最終的な印刷物が得られます。

+0

Dang!私にそれを打つ! –

+0

すべての点を尊重します...静的コンストラクタが最初に実行されません。静的フィールドイニシャライザが最初に実行されます。 – Prankster

+1

A._Aの構築は静的コンストラクタで行われます。コンパイラは、C#静的コンストラクタで宣言されたコードの前に静的コンストラクタ(.cctor)内のすべてのフィールドの初期化をプリペンドします。 –

-1

はい、コンストラクターが呼び出される前に静的フィールドの初期化が完了する必要があります。しかし、コンパイラを非正常な状況に置くと、この規則に従うことができません。

これは興味深いトリックですが、通常のアプリケーションでは起こりません。

1

私は実際にあなたが思っていることをしていると信じています。あなたのテストはそれを伝えるのが難しくなります。 _A

public static string _A = (new A()).I(); 

まずため

あなたinitalizationは、このようにあなたの新しいA(の著作)と_A = nullを、Aの新しいインスタンスを作成します。開始時にはnullだったので、これが初期化であるためです。初期化されると、静的コンストラクタが呼び出され、新しいインスタンスが返されます。

0

コンパイラが期待しているようです。第一

- すべての静的コードは、クラスに(フィールドの最初の、そして静的コンストラクタ)が実行される:

public static string _A = (new A()).I(); 

// and 

static A() 
{ 
    Console.WriteLine("static A()"); 
} 

第二 - クラスのコンストラクタが呼び出されます。

public A() 
{ 
    Console.WriteLine("new A()"); 
    if (_A == null) 
     Console.WriteLine("_A == null"); 
    else 
     Console.WriteLine("_A == " + _A); 
} 

あなたが尋ねますなぜこれが可能ですか?まあ、私の意見では、インスタンスは、すべてのクラス変数が作成時に初期化されることを絶対に必要としません。ただ存在する必要があります。私はこの特定のケースは、すべての静的初期化が行われる前にインスタンスが作成されるため、この考えをサポートしていると思います。

0

つの余分なサイドノート - C#の仕様(私は4.0で探していますが、それはあまりにも3.0にあります)10.5.5.1静的フィールドの初期設定で述べている:

静的コンストラクタ(§10.12)の場合 がクラスに存在する場合、 静的フィールド初期化子を実行すると、その 静的コンストラクタを実行する直前に が発生します。そうでなければ、 静的フィールド初期化子は、そのクラスの静的 フィールドの最初の使用に先立って、実装に依存する時間 で実行されます( )。

あなたには静的コンストラクタがあるので、 "otherwise"句は適用されません。しかし、あなたが静的なコンストラクタを持っていなければ、静的なフィールド初期化子は '実装依存の時間に'実行できることを知ることはあなたの質問に関連する情報だと思います。これは、静的フィールド初期化子が静的フィールド自体にアクセスせずに依存する、ある種のデータ初期化またはオブジェクト作成を行っている場合には重要です。

これは難解ですが、少なくとも実装依存の時間がC#3.0と4.0の間で変更されているように見えます。簡単なソリューションは簡単ですが、静的なコンストラクタを追加するだけです。

関連する問題