Was ist ein Singleton in C #?


181

Was ist ein Singleton und wann sollte ich ihn verwenden?



4
Außerdem ist der Singleton eines der am häufigsten verwendeten und missbrauchten Entwurfsmuster in der OO-Programmierung.
ChaosPandion

3
@Fabiano: Weil es eine Möglichkeit gibt, Kopplungen zu erstellen, die keinen Sinn ergeben (wie kann ich Xmit ihnen sprechen Y? Machen Sie einfach Yeinen Singleton!), Was wiederum zu Schwierigkeiten beim Testen / Debuggen und einem prozeduralen Programmierstil führt. Manchmal sind Singletons notwendig; die meiste Zeit nicht.
Aaronaught

3
Dies ist eine meiner Standardfragen zu Telefoninterviews. Die richtige Antwort lautet: niemals.
Jonnii

3
@jonnii das ist gut, es hilft potenziellen Entwicklern zu warnen, wie dort Chef ist!
Mr. Boy

Antworten:


144

Ein Singleton ist eine Klasse, mit der nur eine Instanz von sich selbst erstellt werden kann - und die einen einfachen Zugriff auf diese Instanz bietet. Die Singleton-Prämisse ist ein Muster für die gesamte Softwareentwicklung.

Es gibt eine C # -Implementierung "Implementieren des Singleton-Musters in C #", die das meiste abdeckt, was Sie wissen müssen - einschließlich einiger guter Ratschläge zur Thread-Sicherheit .

Um ehrlich zu sein, ist es sehr selten, dass Sie einen Singleton implementieren müssen - meiner Meinung nach sollte dies eines der Dinge sein, die Sie beachten sollten, auch wenn es nicht zu oft verwendet wird.


2
nettes Tutorial, aber heiliger Mist, was haben sie mit der
Codeeinrückung gemacht

Hier ist ein direkterer Link zu dem, was ich für die ideale Implementierung im Jahr 2020 halte. Das heißt, " Verwenden des Lazy <T> -Typs von .NET 4 " sowie der Link zum Microsoft-Dokument für Lazy<T> Class.
Chiramisu

52

Sie haben nach C # gefragt. Triviales Beispiel:


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

    private static readonly Singleton _singleton = new Singleton();

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

14
Nicht threadsicher. Zwei Threads können gleichzeitig aufrufen und zwei separate Objekte erstellen.
Alagesan Palani

5
@ Alagesan Palani, in der Tat hast du recht. Ich bin nicht mit den Details der Initialisierung auf Klassenebene vertraut, aber ich denke, die Änderung, die ich vorgenommen habe, behebt das Thread-sichere Problem.
Chris Simmons

3
Sicher, ich zeige NICHT, dass Sie falsch liegen. Ich gebe dem Leser einen Hinweis zur Thread-Sicherheit, damit er vorsichtig ist, wenn er sich damit befassen muss.
Alagesan Palani

9
Nein, ich denke dein Kommentar ist wichtig. Da ein Singleton eine - und nur eine - Instanz liefern soll, eröffnet die Race-Bedingung hier die Möglichkeit, dass mehr als eine Instanz geliefert wird. Sehen Sie sich jetzt die Version mit statischer Feldinitialisierung an. Ich glaube, dies behebt das Thread-Sicherheitsproblem, wenn ich die Dokumente lese und diese SO richtig antworte .
Chris Simmons

1
@ AlagesanPalani, ich sehe, dass Sie angegeben haben, dass einige andere Antworten nicht threadsicher sind. Möchten Sie eine threadsichere Lösung anbieten?
Bonez024

39

Was es ist: Eine Klasse, für die es über die Lebensdauer einer Anwendung nur eine dauerhafte Instanz gibt. Siehe Singleton-Muster .

Wann Sie es verwenden sollten: So wenig wie möglich. Nur wenn Sie absolut sicher sind, dass Sie es brauchen. Ich zögere es, "nie" zu sagen, aber es gibt normalerweise eine bessere Alternative, wie z. B. Abhängigkeitsinjektion oder einfach eine statische Klasse.


16
Ich bin mir nicht sicher, ob eine statische Klasse eine bessere Alternative als ein Singleton ist ... es hängt wirklich von der Situation und der Sprache ab.
Marcgg

5
Statische Klassen verhalten sich nicht wie Singleton, ein Singleton kann als Parameter an Methoden übergeben werden, eine statische Klasse dagegen nicht.
TabbyCool

4
Mit marcgg einverstanden sein - Ich sehe eine statische Klasse nicht als gute Alternative zu Singletons, da Sie immer noch das Problem haben, einen Ersatz bereitzustellen, z. B. beim Testen einer Komponente, die von dieser Klasse abhängt. Ich sehe aber auch unterschiedliche Verwendungszwecke. Eine statische Klasse wird normalerweise für unabhängige Dienstprogrammfunktionen verwendet, die vom Status unabhängig sind, wobei ein Singleton eine tatsächliche Klasseninstanz ist und normalerweise einen Status speichert. Ich stimme vollkommen zu, stattdessen DI zu verwenden, und sage dann Ihrem DI-Container, dass er nur eine einzelne Instanz dieser Klasse verwenden soll.
Pete

9
Ich habe diese Antwort abgelehnt, weil sie mir keine Informationen darüber gibt, wann ich sie verwenden soll. "Nur wenn du es brauchst" gibt mir überhaupt keine Informationen für jemanden, der neu in Singletons ist.
Sergio Tapia

9
@Adkins: DI steht für Dependency Injection (Abhängigkeitsinjektion), wenn Klassenabhängigkeiten (normalerweise) über einen Konstruktor oder eine öffentliche Eigenschaft übergeben werden. DI allein löst das "Distanz" -Problem nicht, wird jedoch normalerweise zusammen mit einem IoC-Container (Inversion-of-Control) implementiert, der weiß, wie Abhängigkeiten automatisch initialisiert werden. Wenn Sie also einen Singleton erstellen, um das Problem "X weiß nicht, wie man Y findet / mit Y spricht" zu lösen, kann eine Kombination aus DI und IoC dasselbe Problem mit einer lockeren Kopplung lösen.
Aaronaught

27

Eine andere Möglichkeit, Singleton in c # zu implementieren, ist mir persönlich vorzuziehen, da Sie anstelle einer Methode auf die Instanz der Singeton-Klasse als Eigenschaft zugreifen können.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

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

        //instance methods
    }

Aber soweit ich weiß, werden beide Wege als "richtig" angesehen, also ist es nur eine Sache des persönlichen Geschmacks.


11
Nicht threadsicher. Zwei Threads können gleichzeitig aufrufen und zwei separate Objekte erstellen.
Alagesan Palani

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();
        }
    }
}

Ich habe Code von dofactory.com genommen , nichts Besonderes , aber ich finde das weitaus besser als Beispiele mit Foo und Bar Buch von Judith Bishop über C # 3.0 Design Patterns enthält ein Beispiel für eine aktive Anwendung im Mac-Dock.

Wenn Sie sich Code ansehen, bauen wir tatsächlich neue Objekte für die for- Schleife auf, sodass ein neues Objekt erstellt wird, die Instanz jedoch wiederverwendet wird, wodurch der alte und der neue Balancer dieselbe Instanz haben. Wie? Dies ist auf das statische Schlüsselwort zurückzuführen, das für die Funktion GetLoadBalancer () verwendet wird. Trotz des unterschiedlichen Serverwerts , der eine zufällige Liste ist, ist das statische Schlüsselwort für GetLoadBalancer () zum Typ selbst und nicht zu einem bestimmten Objekt .

Zusätzlich gibt es überprüfen Sperren hier

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

seit von MSDN

Das Schlüsselwort lock stellt sicher, dass ein Thread keinen kritischen Codeabschnitt eingibt, während sich ein anderer Thread im kritischen Abschnitt befindet. Wenn ein anderer Thread versucht, einen gesperrten Code einzugeben, wartet er blockiert, bis das Objekt freigegeben wird.

Daher wird jedes Mal eine Sperre für den gegenseitigen Ausschluss ausgestellt, auch wenn dies nicht erforderlich ist. Dies ist nicht erforderlich, sodass wir eine Nullprüfung durchführen.

Hoffentlich hilft es beim Löschen von mehr.

Und bitte kommentieren Sie, wenn mein Verständnis falsche Wege weist.


6

Ein Singleton (und dies ist nicht an C # gebunden, es ist ein OO-Entwurfsmuster) ist, wenn Sie zulassen möchten, dass nur EINE Instanz einer Klasse in Ihrer Anwendung erstellt wird. Die Nutzung umfasst normalerweise globale Ressourcen, obwohl ich aus persönlicher Erfahrung sagen werde, dass sie sehr oft die Quelle großer Schmerzen sind.


5

Während es immer nur eine Instanz eines Singletons geben kann, ist dies nicht dasselbe wie eine statische Klasse. Eine statische Klasse kann nur statische Methoden enthalten und kann niemals instanziiert werden, während die Instanz eines Singletons auf dieselbe Weise wie jedes andere Objekt verwendet werden kann.


2

Es ist ein Designmuster und nicht spezifisch für c #. Mehr darüber im Internet und SO, wie in diesem Wikipedia-Artikel .

In der Softwareentwicklung ist das Singleton-Muster ein Entwurfsmuster, mit dem die Instanziierung einer Klasse auf ein Objekt beschränkt wird. Dies ist nützlich, wenn genau ein Objekt benötigt wird, um Aktionen im gesamten System zu koordinieren. Das Konzept wird manchmal auf Systeme verallgemeinert, die effizienter arbeiten, wenn nur ein Objekt vorhanden ist, oder die die Instanziierung auf eine bestimmte Anzahl von Objekten beschränken (z. B. fünf). Einige halten es für ein Anti-Pattern, da es zu häufig verwendet wird, unnötige Einschränkungen in Situationen einführt, in denen eine einzige Instanz einer Klasse nicht erforderlich ist, und den globalen Status in eine Anwendung einführt.

Sie sollten es verwenden, wenn Sie eine Klasse möchten, die nur einmal instanziiert werden kann.


2

Ich benutze es für Suchdaten. Einmal aus DB laden.

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

Was ist ein Singleton?
Es ist eine Klasse, die nur die Erstellung einer Instanz von sich selbst ermöglicht und normalerweise einen einfachen Zugriff auf diese Instanz ermöglicht.

Wann sollten Sie verwenden:
Es hängt von der Situation ab.

Hinweis: Bitte auf DB - Verbindung nicht verwenden, für eine ausführliche Antwort bitte beziehen sich auf die Antwort von @Chad Grants

Hier ist ein einfaches Beispiel für 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;
        }
    }
}

Sie können auch verwenden Lazy<T>, um Ihre zu erstellen Singleton.

Hier finden Sie ein detaillierteres Beispiel für die VerwendungLazy<T>


1

Folgendes ist Singleton: http://en.wikipedia.org/wiki/Singleton_pattern

Ich kenne C # nicht, aber es ist in allen Sprachen dasselbe, nur die Implementierung unterscheidet sich.

Sie sollten Singleton generell vermeiden, wenn es möglich ist, aber in einigen Situationen ist es sehr praktisch.

Entschuldigung für mein Englisch ;)


Ihr Englisch ist in Ordnung :)
FrenkyB

1

Die Singleton-Klasse wird verwendet, um eine einzelne Instanz für die gesamte Anwendungsdomäne zu erstellen.

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; }            
    }
}

In diesem Artikel wird beschrieben, wie wir mit schreibgeschützten Variablen eine thread-sichere Singleton-Klasse erstellen können und wie sie in Anwendungen praktisch eingesetzt werden können.


1

Ich weiß, dass es sehr spät ist, die Frage zu beantworten, aber mit Auto-Property können Sie so etwas tun:

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

Wo Singletonist Ihre Klasse und kann über, in diesem Fall die schreibgeschützte Eigenschaft sein Instance.


0

EX Sie können Singleton für globale Informationen verwenden, die injiziert werden müssen.

In meinem Fall habe ich die Details des protokollierten Benutzers (Benutzername, Berechtigungen usw.) in der globalen statischen Klasse gespeichert. Und als ich versuchte, den Unit Test zu implementieren, konnte ich keine Abhängigkeit in Controller-Klassen einfügen. Daher habe ich meine statische Klasse in ein Singleton-Muster geändert.

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

Wir müssen das Singleton-Entwurfsmuster in C # verwenden, um sicherzustellen, dass nur eine Instanz einer bestimmten Klasse erstellt wird, und dann für die gesamte Anwendung einen einfachen globalen Zugriff auf diese Instanz bereitzustellen.

Echtzeitszenarien, in denen Sie das Singleton-Entwurfsmuster verwenden können: Service-Proxies: Wie wir wissen, ist das Aufrufen einer Service-API eine umfangreiche Operation in einer Anwendung. Der Prozess, der die meiste Zeit in Anspruch nimmt, ist das Erstellen des Service-Clients, um die Service-API aufzurufen. Wenn Sie den Service-Proxy als Singleton erstellen, wird die Leistung Ihrer Anwendung verbessert.

Fassaden: Sie können die Datenbankverbindungen auch als Singleton erstellen, um die Leistung der Anwendung zu verbessern.

Protokolle: In einer Anwendung ist das Ausführen der E / A-Operation für eine Datei eine teure Operation. Wenn Sie Ihren Logger als Singleton erstellen, wird die Leistung der E / A-Operation verbessert.

Datenfreigabe: Wenn Sie konstante Werte oder Konfigurationswerte haben, können Sie diese Werte in Singleton behalten, damit diese von anderen Komponenten der Anwendung gelesen werden können.

Caching: Wie wir wissen, ist das Abrufen der Daten aus einer Datenbank ein zeitaufwändiger Prozess. In Ihrer Anwendung können Sie den Master und die Konfiguration im Speicher zwischenspeichern, um die DB-Aufrufe zu vermeiden. In solchen Situationen kann die Singleton-Klasse verwendet werden, um das Caching mit Thread-Synchronisation auf effiziente Weise zu handhaben, wodurch die Leistung der Anwendung drastisch verbessert wird.

Nachteile des Singleton-Entwurfsmusters in C # Die Nachteile der Verwendung des Singleton-Entwurfsmusters in C # sind folgende:

Unit-Tests sind sehr schwierig, da sie einen globalen Status in eine Anwendung einführen. Dies verringert das Potenzial für Parallelität innerhalb eines Programms, da für den Zugriff auf die Singleton-Instanz in einer Umgebung mit mehreren Threads das Objekt mithilfe der Sperre serialisiert werden muss.

Ich habe dies dem folgenden Artikel entnommen.

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


0

Thread Safe Singleton ohne Verwendung von Sperren und ohne verzögerte Instanziierung.

Diese Implementierung verfügt über einen statischen Konstruktor, sodass sie nur einmal pro Anwendungsdomäne ausgeführt wird.

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

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

}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.