Menu
Coddy logo textTech

IDisposable & using-Anweisung

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 45 von 70.

Einige Objekte halten Ressourcen fest, die der Garbage Collector nicht automatisch bereinigen kann – Dateihandles, Datenbankverbindungen, Netzwerk-Sockets. Die Schnittstelle IDisposable bietet eine standardisierte Möglichkeit, diese Ressourcen freizugeben, wenn du sie nicht mehr benötigst.

Eine Klasse implementiert IDisposable, indem sie eine Dispose()-Methode bereitstellt:

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

Du könntest Dispose() manuell aufrufen, aber was ist, wenn eine Ausnahme auftritt, bevor du diese Zeile erreichst? Die using-Anweisung garantiert, dass die Bereinigung erfolgt, selbst wenn etwas schiefgeht:

using (FileHandler handler = new FileHandler())
{
    // Mit dem Handler arbeiten
}  // Dispose() wird hier automatisch aufgerufen

Modernes C# bietet mit der using-Deklaration eine übersichtlichere Syntax, die das Objekt freigibt, wenn es außerhalb des Gültigkeitsbereichs liegt:

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // Mit handler arbeiten
}  // Dispose() wird aufgerufen, wenn die Methode beendet wird

Die using-Anweisung funktioniert mit jedem Typ, der IDisposable implementiert. Integrierte Klassen wie StreamReader, SqlConnection und HttpClient implementieren alle diese Schnittstelle, wodurch eine ordnungsgemäße Ressourcenverwaltung unkompliziert und zuverlässig wird.

challenge icon

Aufgabe

Einfach

Lass uns einen Datenbankverbindungssimulator erstellen, der eine ordnungsgemäße Ressourcenverwaltung mithilfe der Schnittstelle IDisposable und der Anweisung using demonstriert. Du erstellst eine Klasse, die verfolgt, wann Verbindungen geöffnet und geschlossen werden, und so sicherstellt, dass Ressourcen stets ordnungsgemäß freigegeben werden.

Du wirst deinen Code auf zwei Dateien verteilen:

  • DatabaseConnection.cs: Erstelle eine Klasse DatabaseConnection im Namespace DataAccess, die IDisposable implementiert. Deine Verbindung sollte:
    • Eine Eigenschaft ConnectionName (string, nur lesbar) besitzen, die über den Konstruktor festgelegt wird
    • Über ein privates boolesches Feld verfolgen, ob die Verbindung verworfen wurde
    • Connection opened: {ConnectionName} ausgeben, wenn das Objekt erstellt wird (im Konstruktor)
    • Die Methode Dispose() implementieren, die Connection closed: {ConnectionName} ausgibt – aber nur, wenn die Verbindung noch nicht verworfen wurde (um eine doppelte Freigabe zu verhindern)
    • Eine Methode Query(string sql) besitzen, die Executing on {ConnectionName}: {sql} zurückgibt
  • Program.cs: Demonstriere in deiner Hauptdatei eine ordnungsgemäße Ressourcenverwaltung, indem du die Anweisung using mit deiner Datenbankverbindung verwendest. Erstelle eine Verbindung, führe eine Abfrage aus und lasse den using-Block die Bereinigung automatisch übernehmen.

Du erhältst zwei Eingaben:

  • Den Verbindungsnamen (z. B. MainDB)
  • Die auszuführende SQL-Abfrage (z. B. SELECT * FROM Users)

Verwende eine using-Anweisung, um deine Verbindung zu erstellen. Rufe innerhalb des Blocks die Methode Query auf und gib ihr Ergebnis aus. Wenn der using-Block endet, wird Dispose() automatisch aufgerufen.

Wenn die Eingaben beispielsweise MainDB und SELECT * FROM Users lauten, sollte die Ausgabe folgendermaßen aussehen:

Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDB

Beachte, wie die Verbindung automatisch geschlossen wird, wenn der using-Block endet – du musst dich nie daran erinnern, Dispose() manuell aufzurufen. Dieses Muster stellt sicher, dass Ressourcen immer bereinigt werden, selbst wenn innerhalb des Blocks eine Ausnahme auftritt!

Probier es selbst

using System;
using DataAccess;

class Program
{
    public static void Main(string[] args)
    {
        string connectionName = Console.ReadLine();
        string sqlQuery = Console.ReadLine();
        
        // TODO: Verwende eine 'using'-Anweisung, um eine DatabaseConnection zu erstellen
        // Innerhalb des using-Blocks:
        // 1. Rufe die Query-Methode mit der sqlQuery auf
        // 2. Gib das Ergebnis der Query-Methode aus
        // Die Dispose-Methode wird automatisch aufgerufen, wenn der using-Block endet
        
    }
}
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

Übe selbstständig: Online-C#-Compiler