Thread-sicheres Singleton
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 52 von 70.
Das Singleton-Muster stellt sicher, dass eine Klasse während der gesamten Anwendung nur eine einzige Instanz hat, und bietet einen globalen Zugriffspunkt darauf. Dies ist nützlich für die Verwaltung gemeinsam genutzter Ressourcen wie Konfigurationseinstellungen, Protokollierungsdienste oder Datenbankverbindungen.
Ein einfaches Singleton verwendet einen privaten Konstruktor, um eine externe Instanziierung zu verhindern, und eine statische Eigenschaft, um den Zugriff zu ermöglichen:
public class Logger
{
private static Logger _instance;
private static readonly object _lock = new object();
private Logger() { } // Privater Konstruktor
public static Logger Instance
{
get
{
lock (_lock)
{
if (_instance == null)
_instance = new Logger();
return _instance;
}
}
}
public void Log(string message) => Console.WriteLine(message);
}Die lock-Anweisung gewährleistet Threadsicherheit – wenn mehrere Threads gleichzeitig versuchen, auf Instance zuzugreifen, kann immer nur einer gleichzeitig den kritischen Abschnitt betreten. Ohne dies könnten zwei Threads _instance beide als null sehen und separate Instanzen erstellen.
C# bietet einen einfacheren threadsicheren Ansatz unter Verwendung der statischen Initialisierung:
public class Logger
{
private static readonly Logger _instance = new Logger();
private Logger() { }
public static Logger Instance => _instance;
public void Log(string message) => Console.WriteLine(message);
}Diese Version ist threadsicher, da die CLR garantiert, dass die Initialisierung statischer Felder nur einmal erfolgt. Beide Ansätze stellen sicher, dass Sie immer dieselbe Instanz erhalten:
Logger.Instance.Log("First call");
Logger.Instance.Log("Same instance");Aufgabe
EinfachErstellen wir einen threadsicheren Konfigurationsmanager unter Verwendung des Singleton-Musters. In realen Anwendungen müssen Konfigurationseinstellungen im gesamten Programm zugänglich sein, wobei gleichzeitig sichergestellt wird, dass nur eine Instanz existiert – ein perfekter Anwendungsfall für Singleton.
Du wirst deinen Code auf zwei Dateien aufteilen:
ConfigManager.cs: Erstelle eineConfigManager-Klasse im NamespaceConfiguration, die das Singleton-Muster implementiert. Dein Konfigurationsmanager sollte:- Ein privates statisches Feld besitzen, das die einzige Instanz speichert
- Einen privaten Konstruktor verwenden, um eine externe Instanziierung zu verhindern
- Eine statische
Instance-Eigenschaft bereitstellen, die die einzige Instanz zurückgibt (verwende zur Threadsicherheit den einfacheren Ansatz der statischen Initialisierung) - Ein privates String-Feld
_appNameenthalten, das mit"MyApp"initialisiert wird - Eine
SetAppName(string name)-Methode besitzen, um den App-Namen zu aktualisieren - Eine
GetAppName()-Methode besitzen, die den aktuellen App-Namen zurückgibt
Program.cs: Zeige in deiner Hauptdatei, dass das Singleton korrekt funktioniert, indem du mehrmals auf die Instanz zugreifst und zeigst, dass Änderungen über alle Verweise hinweg erhalten bleiben.
Du erhältst eine Eingabe:
- Einen neuen App-Namen, der festgelegt werden soll (z. B.
ProductionServer)
In deinem Programm:
- Rufe die
ConfigManager-Instanz ab und gib den Standard-App-Namen aus - Rufe die Instanz erneut ab (in einer anderen Variablen) und verwende sie, um den neuen App-Namen aus der Eingabe festzulegen
- Rufe die Instanz ein drittes Mal ab und gib den App-Namen aus, um zu beweisen, dass alle Verweise dieselben Daten gemeinsam nutzen
Wenn die Eingabe beispielsweise ProductionServer lautet, sollte die Ausgabe wie folgt aussehen:
MyApp
ProductionServerDies veranschaulicht den zentralen Vorteil von Singleton: Unabhängig davon, wie oft du auf Instance zugreifst, erhältst du immer dasselbe Objekt mit gemeinsam genutztem Zustand. Der Ansatz der statischen Initialisierung garantiert Threadsicherheit, da die CLR sicherstellt, dass das statische Feld nur einmal initialisiert wird, selbst wenn mehrere Threads gleichzeitig darauf zugreifen.
Probier es selbst
using System;
using Configuration;
class Program
{
public static void Main(string[] args)
{
// Eingabe lesen - der neue Anwendungsname
string newAppName = Console.ReadLine();
// TODO: Die ConfigManager-Instanz abrufen und den Standard-App-Namen ausgeben
// TODO: Die Instanz erneut abrufen (in eine andere Variable) und sie verwenden, um den neuen App-Namen festzulegen
// TODO: Die Instanz ein drittes Mal abrufen und den App-Namen ausgeben, um zu beweisen, dass alle Referenzen dieselben Daten teilen
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler