質問: await Something.Do(Asset.Instance); } ``` MSDNによると静的コンストラクタは`最高で一度だけ実行される`と書かれていました。 `The static constructor for a class executes at most once in a given application domain.` ### 質問 なぜ`await`の中で初めてインスタンスの初期化を行うと`Singleton`の本来の動きにならない(複数回初期化されてしまう)のでしょうか?
回答: まず最初に 静的コンストラクタを勘違いされているようです。 静的コンストラクタとは以下のような書き方をするもので、 プログラム全体で数えて初めてそのクラスが作られた時に一度だけ実行されます。 追記:staticメンバが初めて参照される場合でも呼ばれるようです。その場合でもプログラム全体で実行されるのは一度だけです。 ``` class MyClass { static MyClass() // 通常のコンストラクタの前にstaticが付く { } } ``` 今回の件の要点は、スレッドセーフの話です。 スレッドセーフな作りになってないので、複数のスレッドでAssetが同時に呼ばれると最初の_instanceのnewが終わるまでの間に他のスレッドがif文をすり抜けてしまう事が起こり得ます。 (newが完了するまで_instanceはnullのままなので) 解決方法はいろいろあります。 例としてロックオブジェクトを使うやり方を紹介します。 ただし、このやり方は簡単ですがベストなやり方というわけではないので、 興味を持ったら別の方法も調べて試してみてください。 ``` public class Asset { private static object lockObject = new object(); // lockオブジェクトを作成 private static Asset _instance; public static Asset Instance { get { lock (lockObject) // このスコープ内は一つのスレッドしか通過できず、そのスレッドが完了するまで他のスレッドは待ち状態になる { if (_instance == null) { _instance = new Asset(); } } return _instance; } } private Asset() { // コンストラクタでアセットファイルの読み込みを行う } } ```