71699


題の通り、シングルトンパターンについて調べていましたが、  
いくつかのサイトをみていると

  1. 宣言時に初期化するパターン
  2. 一意のインスタンスを取得する関数内でnullであれば初期化するパターン  
の２通りのパターンがありました。

一つ気になったのが1の場合はどのタイミングでインスタンスが生成されるのかと思いましたが、  
以下で記載するようにMainメソッドで試してみたところ初回呼び出し時に"インスタンス生成"の文字が出力されました。  
このことからどちらも差異がないのかと思っていますが、  
何か違いがあるのか？、どちらが良いのか？、気になりました。  
どちらでもいいのでしょうか。

1の例

[code]

        class Singleton
        {
            // ★ここで new
            private static Singleton singleton = new Singleton();
    
            private Singleton() {
                Console.WriteLine("インスタンス生成");
            }
    
            public static Singleton getInstance() {
                return singleton;
            }
        }
    
[/code]

2の例

[code]

        class Singleton2
        {
            private static Singleton2 singleton2 = null;
    
            private Singleton2() {
                Console.WriteLine("インスタンス生成");
            }
    
            public static Singleton2 getInstance() {
                // ★ここでnullであれば new
                if (singleton2 == null) {
                    singleton2 = new Singleton2();
                }
                return singleton2;
            }
        }
    
[/code]

Mainでのテストコード

[code]

    static void Main(string[] args) {
        Console.WriteLine("start");
        Singleton obj1 = Singleton.getInstance();
        Singleton2 obj2 = Singleton2.getInstance();
        Singleton obj3 = Singleton.getInstance();
        Singleton2 obj4 = Singleton2.getInstance();
    }
    
[/code]


CC BY-SA 4.0
2020-11-03T12:40:35.027
71697
2020-11-03T23:08:08.683
42136
question
c#
C#でのSingletonパターン実装で宣言時に初期化する場合とインスタンスを取得する関数内で実装することの差異はありますか？


1は最初に静的メンバが参照される時に、一度だけ [静的コンストラクタ](https://docs.microsoft.com/ja-
jp/dotnet/csharp/programming-guide/classes-and-structs/static-constructors)
が実行され、インスタンスが初期化されます。

2は毎回静的メンバの null チェックをし、nullである時にインスタンスを作成します。

1は余計なチェックを省略できるというメリットがありますが、静的コンストラクタのリンク先の説明を読んで頂くと判りますが、いくつか注意しないといけない点もあります。  
どちらが良い悪いというものでもないので、メリット・デメリットを把握した上で、どちらを採用するかを決めればよいかと思います。


CC BY-SA 4.0
2020-11-03T13:36:28.953
71699
2020-11-03T13:48:23.840
2020-11-03T13:48:23.840
41943
41943
71697
answer


既にradianさんがよい回答をされていますが、補足で。

> 一つ気になったのが1の場合はどのタイミングでインスタンスが生成されるのかと思いましたが、  
>  以下で記載するようにMainメソッドで試してみたところ初回呼び出し時に"インスタンス生成"の文字が出力されました。

手元の環境（Windows 10 20H2、.NET Framework
4.8）では、`Singleton`は`start`よりも前に初期化されていました。  
既にコメントされていますが、静的メンバーの初期化は静的コンストラクターのように動作します。そのため、静的コンストラクターの初期化タイミングが未定なのと同じく、静的メンバーの初期化タイミングも未定です。複数の型が相互に依存していると、静的メンバーの初期化最中に別の型の静的メンバーの初期化が走り、メンバー参照されてしまったりという状況も発生します。

また、[Type Constructor Guidelines](https://docs.microsoft.com/en-
us/dotnet/standard/design-guidelines/constructor#type-constructor-guidelines)で

> DO NOT throw exceptions from static constructors.

とあるように、宣言時に初期化するパターンシングルトンにおいては例外を発生させてはいけません。例外が発生した場合、`Singleton`クラスそのものの初期化に失敗したことを表し、`TypeInitializationException`が発生します。明に実行したコードではないため`catch`できずプロセスが停止されてしまいます。

* * *

いろいろとC#的でないコードでしたので、参考までに最新の書式で書き直してみました。

[code]

    class Singleton1 {
        // 一度のみ初期化されるプロパティの書式
        public static Singleton1 Instance { get; } = new Singleton1();
    
        Singleton1() => Console.WriteLine("インスタンス生成1");
    }
    
    class Singleton2 {
        // あらかじめ`0`初期化されているので改めて`null`初期化する必要はない
        static Singleton2 instance;
    
        // 毎回実行されるプロパティの書式
        public static Singleton2 Instance => instance ??= new Singleton2();
    
        Singleton2() => Console.WriteLine("インスタンス生成2");
    }
    
[/code]


CC BY-SA 4.0
2020-11-03T23:08:08.683
71704
2020-11-03T23:08:08.683
4236
71697
answer