Menu
Coddy logo textTech

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");
challenge icon

Aufgabe

Einfach

Lassen Sie uns einen threadsicheren Konfigurationsmanager mit dem Singleton-Muster erstellen. In realen Anwendungen müssen Konfigurationseinstellungen im gesamten Programm zugänglich sein, während gleichzeitig sichergestellt werden muss, dass nur eine Instanz existiert – ein perfekter Anwendungsfall für das Singleton-Muster.

Sie werden Ihren Code in zwei Dateien organisieren:

  • ConfigManager.cs: Erstellen Sie eine ConfigManager-Klasse im Namespace Configuration, die das Singleton-Muster implementiert. Ihr Konfigurationsmanager sollte:
    • Ein privates statisches Feld besitzen, um die einzige Instanz zu halten
    • Einen privaten Konstruktor verwenden, um eine externe Instanziierung zu verhindern
    • Eine statische Instance-Eigenschaft bereitstellen, welche die einzige Instanz zurückgibt (verwenden Sie den einfacheren Ansatz der statischen Initialisierung für Threadsicherheit)
    • Ein privates String-Feld _appName enthalten, das mit "MyApp" initialisiert ist
    • 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: Demonstrieren Sie in Ihrer Hauptdatei, dass das Singleton korrekt funktioniert, indem Sie mehrmals auf die Instanz zugreifen und zeigen, dass Änderungen über alle Referenzen hinweg bestehen bleiben.

Sie erhalten eine Eingabe:

  • Einen neuen Anwendungsnamen, der gesetzt werden soll (z. B. ProductionServer)

In Ihrem Programm:

  1. Rufen Sie die ConfigManager-Instanz ab und geben Sie den Standard-App-Namen aus
  2. Rufen Sie die Instanz erneut ab (in eine andere Variable) und verwenden Sie diese, um den neuen App-Namen aus der Eingabe zu setzen
  3. Rufen Sie die Instanz ein drittes Mal ab und geben Sie den App-Namen aus, um zu beweisen, dass alle Referenzen dieselben Daten teilen

Wenn die Eingabe beispielsweise ProductionServer ist, sollte die Ausgabe wie folgt aussehen:

MyApp
ProductionServer

Dies demonstriert den Kernvorteil des Singletons – egal wie oft Sie auf Instance zugreifen, Sie erhalten immer dasselbe Objekt mit gemeinsamem 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
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung