C#のシングルトンとは何ですか?


182

シングルトンとは何ですか、いつ使用する必要がありますか?



4
また、シングルトンは、OOプログラミングで最も広く使用され、悪用されている設計パターンの1つです。
ChaosPandion、2010年

3
@Fabiano:意味のない結合を作成する方法があるため(どうすれXば話ができYますか?Yシングルトンを作成するだけです!)、テスト/デバッグと手続き型のプログラミングスタイルが困難になります。時にはシングルトンが必要です。ほとんどの場合、そうではありません。
アーロノート

3
これは私の標準的な電話インタビューの質問の1つです。正解は次のとおりです。
jonnii 2010年

3
@jonniiいいですね、それは上司がどんな人なのかを将来の開発者に警告するのに役立ちます!
ボーイ氏2016

回答:


145

シングルトンは、それ自体のインスタンスを1つだけ作成することを許可するクラスであり、そのインスタンスへのシンプルで簡単なアクセスを提供します。シングルトンの前提は、ソフトウェア開発全体にわたるパターンです。

C#の実装" C#でのシングルトンパターンの実装"があり、スレッドの安全性に関するいくつかの優れたアドバイスなど、知っておく必要のあることのほとんどをカバーしています。

正直に言うと、シングルトンを実装する必要があることは非常にまれです-私の意見では、あまり頻繁に使用されていなくても、それはあなたが知っておくべきことの1つであるはずです。


2
すばらしいチュートリアルですが、コードのインデントに対して何をしたのでしょうか
Inspi

これが、2020年の理想的な実装だと私が考えるものへのより直接的なリンクです。つまり、「。NET 4のLazy <T>タイプの使用」と、Microsoft DocへのリンクLazy<T> Classです。
ちらみす

52

あなたはC#を求めました。簡単な例:


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
スレッドセーフではありません。2つのスレッドが同時に呼び出し、2つの別個のオブジェクトを作成できます。
Alagesan Palani 2015

5
@Alagesan Palani、確かにあなたは正しい。私はクラスレベルの初期化の低レベルの詳細には堪能ではありませんが、私が行った変更はスレッドセーフの懸念に対処していると思います。
Chris Simmons

3
確かに、私はあなたが間違っていることを指摘していません。スレッドセーフについて読者にヒントを与えているので、スレッドセーフに対処する必要がある場合は注意が必要です。
Alagesan Palani

9
いいえ、あなたのコメントは重要だと思います。シングルトンが1つのインスタンスのみを配信することになっているとすると、ここでの競合状態により、複数のインスタンスが配信される可能性があります。静的フィールドを初期化したバージョンを今すぐ確認してください。私がドキュメントこのSOの答えを正しく読んだ場合、これはスレッドセーフの問題を修正すると思います。
Chris Simmons

1
@AlagesanPalaniさん、他にもいくつかの回答はスレッドセーフではないとのことですが、スレッドセーフなソリューションを提供していただけませんか?
Bonez024

39

概要:アプリケーションの存続期間全体で1つの永続的なインスタンスのみが存在するクラス。シングルトンパターンを参照してください。

使用する場合:可能な限り少ない。あなたがそれが必要だと絶対に確信している場合にのみ。私は「絶対にしない」とは言いたがりませんが、通常は、依存性注入や単に静的クラスなど、より優れた代替手段があります。


16
静的クラスがシングルトンより優れた代替手段であるかどうかはわかりません...それは本当に状況と言語に依存します。
marcgg、2010年

5
静的クラスはシングルトンと同じように動作しません。シングルトンはパラメーターとしてメソッドに渡すことができますが、静的クラスはできません。
TabbyCool 2010年

4
marcggに同意します。たとえば、このクラスに依存するコンポーネントのテスト中など、まだ代替クラスを提供する問題があるため、静的クラスをシングルトンの代わりとして使用することはできません。しかし、私はさまざまな用途も見ています。静的クラスは通常、状態に依存しない独立したユーティリティ関数に使用されます。シングルトンは実際のクラスインスタンスであり、通常は状態を格納します。代わりにDIを使用することに完全に同意し、そのクラスの単一のインスタンスのみを使用するようにDIコンテナーに指示します。
Pete

9
いつ使用するかについての情報が得られないため、この回答には反対票を入れました。「あなたがそれを必要とするときだけ」は、シングルトンに新しい人のための情報を私にまったく与えません。
セルジオタピア2010年

9
@Adkins:DIはDependency Injectionを表します。これは、クラスの依存関係が(通常)コンストラクターまたはパブリックプロパティを通じて渡されることを意味します。DIだけでは「距離」の問題は解決しませんが、通常、依存関係を自動的に初期化する方法を知っている制御の反転(IoC)コンテナーと一緒に実装されます。そのため、「XがYを見つけて話す方法がわからない」という問題を解決するためにシングルトンを作成する場合、DIとIoCを組み合わせることで、より緩い結合で同じ問題を解決できます。
アーロノート

27

c#でシングルトンを実装する別の方法として、メソッドではなくプロパティとしてシングルトンクラスのインスタンスにアクセスできるため、個人的にはこの方法を好みます。

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }

しかし、まあ、私が知っている限り、両方の方法は「正しい」と考えられているので、それは個人的な趣味のものです。


11
スレッドセーフではありません。2つのスレッドが同時に呼び出し、2つの別個のオブジェクトを作成できます。
Alagesan Palani 2015

11
using System;
using System.Collections.Generic;
class MainApp
{
    static void Main()
    {
        LoadBalancer oldbalancer = null;
        for (int i = 0; i < 15; i++)
        {
            LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();

            if (oldbalancer == balancerNew && oldbalancer != null)
            {
                Console.WriteLine("{0} SameInstance {1}", oldbalancer.Server, balancerNew.Server);
            }
            oldbalancer = balancerNew;
        }
        Console.ReadKey();
    }
}

class LoadBalancer
{
    private static LoadBalancer _instance;
    private List<string> _servers = new List<string>();
    private Random _random = new Random();

    private static object syncLock = new object();

    private LoadBalancer()
    {
        _servers.Add("ServerI");
        _servers.Add("ServerII");
        _servers.Add("ServerIII");
        _servers.Add("ServerIV");
        _servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
        if (_instance == null)
        {
            lock (syncLock)
            {
                if (_instance == null)
                {
                    _instance = new LoadBalancer();
                }
            }
        }

        return _instance;
    }

    public string Server
    {
        get
        {
            int r = _random.Next(_servers.Count);
            return _servers[r].ToString();
        }
    }
}

私はdofactory.comからコードを取得しましたが、それほど凝ったものではありませんが、Jooth BishopがC#3.0で追加したFoo and Barの例のデザインパターンよりもはるかに優れていることがわかります

コードを見ると、実際には新しいオブジェクトがforループで構築されているため、新しいオブジェクトが作成されますが、oldbalancerとnewbalancerが同じインスタンスを持つインスタンスが再利用されます。方法 これは、関数GetLoadBalancer()静的キーワードが使用されているため、ランダムリストである別のサーバー値があるにもかかわらず、GetLoadBalancer()の静的は、特定のオブジェクトではなくタイプ自体に属しています。

さらに、ここにはダブルチェックロックがあります

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

MSDNから

lockキーワードは、別のスレッドがクリティカルセクションにある間、1つのスレッドがコードのクリティカルセクションに入らないようにします。別のスレッドがロックされたコードを入力しようとすると、オブジェクトが解放されるまで待機、ブロックされます。

そのため、必要がない場合でも、相互排除ロックが毎回発行されるため、nullチェックが行われます。

うまくいけば、それはより多くをクリアするのに役立ちます。

そして、私の理解が間違った方向を向いている場合はコメントしてください。


6

シングルトン(これはC#に関連付けられていません。これはOO設計パターンです)は、アプリケーション全体でクラスのインスタンスを1つだけ作成できるようにする場合です。使用量には通常、グローバルリソースが含まれますが、個人的な経験から言うと、非常に多くの場合、大きな痛みの原因になります。


5

シングルトンのインスタンスは1つしか存在できませんが、静的クラスとは異なります。静的クラスには静的メソッドのみを含めることができ、インスタンス化することはできませんが、シングルトンのインスタンスは他のオブジェクトと同じように使用できます。


2

これは設計パターンであり、c#に固有のものではありません。このWikipediaの記事のように、インターネットとSO全体の詳細について。

ソフトウェアエンジニアリングでは、シングルトンパターンは、クラスのインスタンス化を1つのオブジェクトに制限するために使用される設計パターンです。これは、システム全体でアクションを調整するために1つのオブジェクトのみが必要な場合に役立ちます。この概念は、オブジェクトが1つだけ存在する場合、またはインスタンス化を特定の数のオブジェクト(たとえば、5つ)に制限する場合に、より効率的に動作するシステムに一般化されることがあります。一部は、それが過度に使用されていると判断してアンチパターンと見なし、クラスの唯一のインスタンスが実際には必要とされない状況で不要な制限を導入し、グローバル状態をアプリケーションに導入します。

一度だけインスタンス化できるクラスが必要な場合は、これを使用する必要があります。


2

ルックアップデータに使用します。DBから1回ロードします。

public sealed class APILookup
    {
        private static readonly APILookup _instance = new APILookup();
        private Dictionary<string, int> _lookup;

        private APILookup()
        {
            try
            {
                _lookup = Utility.GetLookup();
            }
            catch { }
        }

        static APILookup()
        {            
        }

        public static APILookup Instance
        {
            get
            {
                return _instance;
            }
        }
        public Dictionary<string, int> GetLookup()
        {
            return _lookup;
        }

    }

2

シングルトンとは:
これは、それ自体の1つのインスタンスの作成のみを許可するクラスであり、通常、そのインスタンスへの単純なアクセスを提供します。

いつ使うべきか:
状況による。

注:db接続では使用しないでください。詳細な回答について、@ Chad Grantの回答を参照してください

の簡単な例を次に示しますSingleton

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

を使用してLazy<T>を作成することもできますSingleton

使用した詳細な例については、ここ参照してくださいLazy<T>


1

シングルトンは次のとおりです。http//en.wikipedia.org/wiki/Singleton_pattern

C#は知りませんが、実際にはすべての言語で同じであり、実装のみが異なります。

可能な場合は通常、シングルトンを避ける必要がありますが、状況によっては非常に便利です。

私の英語でごめんね;)


あなたの英語は大丈夫です:)
FrenkyB

1

シングルトンクラスは、アプリケーションドメイン全体の単一のインスタンスを作成するために使用されます。

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    public static Singleton Instance
    {
        get { return singletonInstance; }            
    }
}

、この記事では説明している私たちは読み取り専用変数とアプリケーションでの実用化を使用してスレッドセーフなシングルトンクラスを作成する方法。


1

私は質問に答えるのが非常に遅いことを知っていますが、自動プロパティであなたはそのようなことをすることができます:

public static Singleton Instance { get; } = new Singleton();

Singletonクラスはどこにあり、経由することができますInstance。この場合は、読み取り専用プロパティです。


0

EX注入する必要があるグローバル情報にシングルトンを使用できます。

私の場合、ログに記録されたユーザーの詳細(ユーザー名、権限など)をグローバル静的クラスに保持していました。ユニットテストを実装しようとしたときに、コントローラークラスに依存関係を注入する方法がありませんでした。したがって、静的クラスをシングルトンパターンに変更しました。

public class SysManager
{
    private static readonly SysManager_instance = new SysManager();

    static SysManager() {}

    private SysManager(){}

    public static SysManager Instance
    {
        get {return _instance;}
    }
}

http://csharpindepth.com/Articles/General/Singleton.aspx#cctor


0

特定のクラスのインスタンスを1つだけ作成し、そのインスタンスへの単純なグローバルアクセスをアプリケーション全体に提供する必要がある場合は、C#でシングルトンデザインパターンを使用する必要があります。

シングルトンデザインパターンを使用できるリアルタイムシナリオ:サービスプロキシ:ご存知のように、サービスAPIの呼び出しは、アプリケーションでの広範な操作です。ほとんどの時間を費やしているプロセスは、サービスAPIを呼び出すためにサービスクライアントを作成しています。サービスプロキシをシングルトンとして作成すると、アプリケーションのパフォーマンスが向上します。

ファサード:データベース接続をシングルトンとして作成して、アプリケーションのパフォーマンスを向上させることもできます。

ログ:アプリケーションでは、ファイルに対するI / O操作の実行は負荷の高い操作です。ロガーをシングルトンとして作成すると、I / O操作のパフォーマンスが向上します。

データ共有:定数値または構成値がある場合は、これらの値をシングルトンに保持して、アプリケーションの他のコンポーネントから読み取れるようにすることができます。

キャッシュ:ご存知のように、データベースからのデータのフェッチは時間のかかるプロセスです。アプリケーションでは、マスターと設定をメモリにキャッシュして、DB呼び出しを回避できます。このような状況では、Singletonクラスを使用して、スレッド同期によるキャッシュを効率的に処理し、アプリケーションのパフォーマンスを大幅に向上させることができます。

C#でのシングルトンデザインパターンの短所C#でのシングルトンデザインパターンの短所は次のとおりです。

ユニットテストは、アプリケーションにグローバルな状態を導入するため、非常に困難です。マルチスレッド環境でシングルトンインスタンスにアクセスするには、ロックを使用してオブジェクトをシリアル化する必要があるため、プログラム内での並列処理の可能性が低くなります。

これは次の記事から引用しています。

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

ロックを使用せず、遅延インスタンス化を行わないスレッドセーフシングルトン。

この実装には静的コンストラクターがあるため、アプリケーションドメインごとに1回だけ実行されます。

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

    public static Singleton Instance { get; } = new Singleton();

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.