静的コンストラクターはどのように機能しますか?
-
29-10-2019 - |
質問
これが私が想定したシーケンスです
- 静的コンストラクターの開始
- 静的コンストラクターの終了
- メインの開始
- MyMethodの開始
- メインの終わり
どのシナリオでも、2より前に4が開始される場合、私は失敗します。可能ですか?
解決
ここで質問したのは1つだけですが、 すべき質問が12ほどあるので、すべて回答します。
これが私が想定したシーケンスです
- クラスコンストラクターの開始(
cctor
とも呼ばれます)- cctorの終わり
- メインの開始
- MyMethodの開始
これは正しいですか?
いいえ。正しい順序は次のとおりです。
- プログラムのcctorの開始(ある場合)。ありません。
- プログラムのcctorの終わり(ある場合)。ありません。
- メインの開始
- MyClassのcctorの開始
- MyClassのcctorの終了
- MyClass.MyMethodの開始
静的フィールド初期化子がある場合はどうなりますか?
CLRは、静的フィールド初期化子が実行される順序を変更できる場合があります。詳細については、この件に関するJonのページを参照してください。
静的コンストラクターと型初期化子の違い そのクラスのcctorが完了する前に、
MyMethod
のような静的メソッドを呼び出すことは可能ですか?はい。 cctor自体がMyMethodを呼び出す場合、明らかにMyMethodはcctorが完了する前に呼び出されます。
cctorはMyMethodを呼び出しません。 MyClassのcctorが完了する前に、
MyMethod
のような静的メソッドを呼び出すことは可能ですか?はい。 cctorがMyMethodを呼び出す別のタイプを使用する場合、MyClasscctorが完了する前にMyMethodが呼び出されます。
直接または間接的にMyMethodを呼び出すcctorはありません! MyClassのcctorが完了する前に、
MyMethod
のような静的メソッドを呼び出すことは可能ですか?いいえ。
複数のスレッドが関係している場合でも、それは当てはまりますか?
はい。静的メソッドを任意のスレッドで呼び出す前に、cctorは1つのスレッドで終了します。
cctorを複数回呼び出すことはできますか? 2つのスレッドの両方がcctorを実行するとします。
関係するスレッドの数に関係なく、cctorは最大で1回呼び出されることが保証されています。 2つのスレッドがMyMethodを「同時に」呼び出すと、それらは競合します。そのうちの1人はレースに負け、MyClasscctorが勝利スレッドで完了するまでブロックします。
失われたスレッドは、cctorが完了するまでブロックしますか? 本当に?
本当に。
では、勝ったスレッドのcctorが、以前に負けたスレッドによって取得されたロックをブロックするコードを呼び出した場合はどうなるでしょうか。
次に、古典的なロック順序の逆転条件があります。プログラムがデッドロックします。永遠に。
それは危険なようです。デッドロックを回避するにはどうすればよいですか?
それを行うときに痛い場合は、それをやめる。 cctorでブロックできるようなことは絶対にしないでください。
複雑なセキュリティ要件を適用するためにcctor初期化セマンティクスに依存するのは良い考えですか?そして、ユーザーとの対話を行うcctorを用意するのは良い考えですか?
どちらも良い考えではありません。私のアドバイスは、メソッドのセキュリティに影響を与える前提条件が満たされていることを確認するための別の方法を見つける必要があるということです。
他のヒント
MSDN によると、静的コンストラクター:
クラスを初期化するために静的コンストラクターが自動的に呼び出されます 最初のインスタンスが作成される前、または静的メンバーが作成される前 参照。
したがって、静的コンストラクターは、静的メソッド
MyClass.MyMethod()
が呼び出される前に呼び出されます(もちろん、静的構築または静的フィールドの初期化中にも呼び出されないことを前提としています)。現在、その
static constructor
で非同期を実行している場合は、それを同期するのがあなたの仕事です。
#3は実際には#1です。静的初期化は、それが属するクラスを最初に使用するまで開始されません。
MyMethod
が静的コンストラクターまたは静的初期化ブロックから呼び出される場合は可能です。静的コンストラクターから直接または間接的にMyMethod
を呼び出さない場合は、問題ありません。
ドキュメントから(私の強調):
クラスを初期化するために静的コンストラクターが自動的に呼び出されます 最初のインスタンスが作成される前または静的メンバーが作成される前 参照。
4が常に2の後に来ることを保証できます(静的メソッドからクラスのインスタンスを作成しない場合)が、1と3には同じではありません。
静的コンストラクターは、mymethodが実行される前に呼び出されます。ただし、2の前に4が呼び出された場合に失敗した場合は、設計を再考することをお勧めします。とにかく静的コンストラクターで複雑なことをするべきではありません。
CLRは、静的メンバーにアクセスする前に静的コンストラクターが実行されることを保証します。しかし、あなたのデザインは少し臭いです。次のようなことを行う方が簡単です: ジェネラコディセタグプレ
設計では、認証が失敗した場合、MyMethodの実行を防ぐ唯一の方法は、例外をスローすることです。
メソッドが実行される前に、静的クラスのコンストラクターが呼び出されていることが保証されます。例: ジェネラコディセタグプレ
出力:
Enterキーを押します
// Enterキーを押した後
こんにちは...
こんにちは!
こんにちは!
状況が悪化する実際の順序は次のとおりです。
-
Main
の開始 - 静的
MyClass
コンストラクターの開始 - 静的
MyClass
コンストラクターの終了 -
MyMethod
の開始 -
Main
の終わり
または、デバッガーでステップスルーすることもできます。