web-dev-qa-db-ja.com

静的コンストラクタはどのように機能しますか?

namespace MyNameSpace
{
    static class MyClass
    {
        static MyClass()
        {
            //Authentication process.. User needs to enter password
        }

        public static void MyMethod()
        {
            //Depends on successful completion of constructor
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass.MyMethod();
        }
    }
}

これが私が想定したシーケンスです

  1. 静的コンストラクタの開始
  2. 静的コンストラクターの終わり
  3. メインの開始
  4. MyMethodの開始
  5. メインの終わり

さて、どのシナリオでも、4が2の前に開始する場合、私はねじ込まれています。出来ますか?

80
om471987

ここでは1つの質問しかしませんでしたが、質問は12か所ほどありますする必要がありますなので、すべてお答えします。

これが私が想定したシーケンスです

  1. クラスコンストラクターの開始(cctorとも呼ばれます)
  2. 俳優の終わり
  3. メインの開始
  4. myMethodの開始

これは正しいです?

いいえ。正しい順序は次のとおりです。

  1. 存在する場合、プログラムのcctorの開始。存在しない。
  2. 存在する場合、プログラムのcctorの終わり。存在しない。
  3. メインの開始
  4. MyClassのcctorの開始
  5. MyClassのcctorの終わり
  6. MyClass.MyMethodの開始

静的フィールド初期化子がある場合はどうなりますか?

CLRは、静的フィールド初期化子が実行される順序を変更できる場合があります。詳細については、件名に関するJonのページを参照してください。

静的コンストラクタと型初期化子の違い

そのクラスのcctorが完了する前にMyMethodのような静的メソッドが呼び出される可能性はありますか?

はい。 cctor自体がMyMethodを呼び出す場合、明らかにcctorが完了する前にMyMethodが呼び出されます。

CctorはMyMethodを呼び出しません。 MyClassのcctorが完了する前にMyMethodのような静的メソッドを呼び出すことは可能ですか?

はい。 cctorが別の型を使用し、そのcctorがMyMethodを呼び出す場合、MyClass cctorが完了する前にMyMethodが呼び出されます。

直接または間接的にMyMethodを呼び出すcctorはありません! MyClassのcctorが完了する前にMyMethodのような静的メソッドを呼び出すことは可能ですか?

番号。

複数のスレッドが関係していても、それは本当ですか?

はい。 cctorは、静的メソッドが任意のスレッドで呼び出される前に、1つのスレッドで終了します。

Cctorを複数回呼び出すことはできますか? 2つのスレッドが両方ともcctorを実行するとします。

関係するスレッドの数に関係なく、cctorは最大で1回呼び出されることが保証されています。 2つのスレッドが「同時に」MyMethodを呼び出すと、競合します。それらの1つはレースに敗れ、MyClass cctorが勝者のスレッドで完了するまでブロックします。

失われたスレッドblocks cctorが完了するまで? 本当に

本当に。

では、winningスレッドのcctorが、以前にlosingスレッドが取得したロックをブロックするコードを呼び出すとどうなるでしょうか。

次に、古典的なロック順序反転条件があります。プログラムのデッドロック。永遠に。

危険そうです。デッドロックを回避するにはどうすればよいですか?

あなたがそれをするときにそれが痛いなら、-それをやめるcctorでブロックできるようなことをしないでください

複雑なセキュリティ要件を強制するためにcctorの初期化セマンティクスに依存することは良い考えですか?そして、ユーザーとの対話を行うcctorを用意するのは良い考えでしょうか?

どちらも良いアイデアではありません。私のアドバイスは、メソッドのセキュリティに影響を与える前提条件が満たされていることを確認する別の方法を見つける必要があるということです。

217
Eric Lippert

[〜#〜] msdn [〜#〜] によると、静的コンストラクタ:

最初のインスタンスが作成される前、または静的メンバーが参照される前に、静的コンストラクターが自動的に呼び出されてクラスを初期化します。

したがって、静的コンストラクターは、静的メソッドMyClass.MyMethod()が呼び出される前に呼び出されます(も呼び出されない静的構築または静的フィールドの初期化中に呼び出されます)もちろん)。

ここで、非同期で何かをしている場合、static constructor、それを同期するのはあなたの仕事です。

23

#3は実際には#1です。静的な初期化は、それが属するクラスが最初に使用されるまで開始されません。

MyMethodが静的コンストラクターまたは静的初期化ブロックから呼び出された場合、それは可能です。静的コンストラクターから直接または間接的にMyMethodを呼び出さない場合は、問題ありません。

11
dasblinkenlight

documentation (私の強調)から:

静的コンストラクターが自動的に呼び出され、クラスを初期化します最初のインスタンスの前が作成されますまたは静的メンバーが参照されます

9
ken

4が常に2の後に来ることを保証できます(静的メソッドからクラスのインスタンスを作成しない場合)。ただし、1と3には同じことが当てはまりません。

2

静的コンストラクターは、mymethodが実行される前に呼び出されます。ただし、4が2の前に呼び出された場合にねじ込まれている場合は、設計を再考することをお勧めします。とにかく静的コンストラクタで複雑なことをするべきではありません。

2
Umair

CLRは、静的メンバーがアクセスされる前に静的コンストラクターが実行されることを保証します。ただし、デザインは少し臭いです。次のようなことをするほうが簡単です:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

設計上、認証が失敗した場合、MyMethodが実行されないようにする唯一の方法は、例外をスローすることです。

2
phoog

メソッドが実行される前に、静的クラスのコンストラクターが呼び出されていることが保証されます。例:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

出力:

Enterキーを押します

// Enterキーを押した後

こんにちは...

こんにちは!

こんにちは!

2
haiyyu

以下に、実際の順序を示します。

  1. Mainの開始
  2. 静的MyClassコンストラクタの開始
  3. 静的MyClassコンストラクターの終わり
  4. MyMethodの開始
  5. Mainの終わり
1
user370770

または、デバッガーをステップ実行できます。

0
saille