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 Sie mit ihnen fertig sind.
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;
}
}
}Sie könnten Dispose() manuell aufrufen, aber was passiert, wenn eine Exception auftritt, bevor Sie diese Zeile erreichen? 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 aufgerufenModernes C# bietet eine sauberere Syntax mit der using-Deklaration, die das Objekt freigibt, wenn es den Gültigkeitsbereich verlässt:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Mit dem Handler arbeiten
} // Dispose() wird aufgerufen, wenn die Methode beendet wirdDie using-Anweisung funktioniert mit jedem Typ, der IDisposable implementiert. Integrierte Klassen wie StreamReader, SqlConnection und HttpClient implementieren alle diese Schnittstelle, was eine ordnungsgemäße Ressourcenverwaltung unkompliziert und zuverlässig macht.
Aufgabe
EinfachLassen Sie uns einen Datenbankverbindungssimulator erstellen, der die ordnungsgemäße Ressourcenverwaltung mithilfe der Schnittstelle IDisposable und der using-Anweisung demonstriert. Sie werden eine Klasse erstellen, die verfolgt, wann Verbindungen geöffnet und geschlossen werden, um sicherzustellen, dass Ressourcen immer ordnungsgemäß freigegeben werden.
Sie werden Ihren Code auf zwei Dateien aufteilen:
DatabaseConnection.cs: Erstellen Sie eine KlasseDatabaseConnectionim NamespaceDataAccess, dieIDisposableimplementiert. Ihre Verbindung sollte:- Über eine Eigenschaft
ConnectionName(String, schreibgeschützt) verfügen, die über den Konstruktor gesetzt wird - Mithilfe eines privaten booleschen Feldes verfolgen, ob die Verbindung bereits freigegeben (disposed) wurde
Connection opened: {ConnectionName}ausgeben, wenn das Objekt erstellt wird (im Konstruktor)- Die Methode
Dispose()implementieren, umConnection closed: {ConnectionName}auszugeben – aber nur, wenn sie nicht bereits freigegeben wurde (um eine doppelte Freigabe zu verhindern) - Über eine Methode
Query(string sql)verfügen, dieExecuting on {ConnectionName}: {sql}zurückgibt
- Über eine Eigenschaft
Program.cs: Demonstrieren Sie in Ihrer Hauptdatei die ordnungsgemäße Ressourcenverwaltung, indem Sie dieusing-Anweisung mit Ihrer Datenbankverbindung verwenden. Erstellen Sie eine Verbindung, führen Sie eine Abfrage aus und lassen Sie denusing-Block die Bereinigung automatisch übernehmen.
Sie erhalten zwei Eingaben:
- Den Verbindungsnamen (z. B.
MainDB) - Die auszuführende SQL-Abfrage (z. B.
SELECT * FROM Users)
Verwenden Sie eine using-Anweisung, um Ihre Verbindung zu erstellen. Rufen Sie innerhalb des Blocks die Methode Query auf und geben Sie deren Ergebnis aus. Wenn der using-Block endet, wird Dispose() automatisch aufgerufen.
Wenn die Eingaben beispielsweise MainDB und SELECT * FROM Users lauten, sollte die Ausgabe wie folgt aussehen:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBBeachten Sie, wie die Verbindung automatisch geschlossen wird, wenn der using-Block endet – Sie müssen nie daran denken, Dispose() manuell aufzurufen. Dieses Muster stellt sicher, dass Ressourcen immer bereinigt werden, selbst wenn innerhalb des Blocks eine Exception auftritt!
Spickzettel
Die Schnittstelle IDisposable bietet eine Standardmethode zur Freigabe von Ressourcen, die der Garbage Collector nicht automatisch bereinigen kann (Dateihandles, Datenbankverbindungen, Netzwerksockets).
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;
}
}
}Die using-Anweisung garantiert, dass die Bereinigung automatisch erfolgt, selbst wenn Ausnahmen auftreten:
using (FileHandler handler = new FileHandler())
{
// Mit dem Handler arbeiten
} // Dispose() wird hier automatisch aufgerufenModernes C# bietet eine sauberere Syntax mit der using-Deklaration:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Mit dem Handler arbeiten
} // Dispose() wird aufgerufen, wenn die Methode beendet wirdDie using-Anweisung funktioniert mit jedem Typ, der IDisposable implementiert, einschließlich integrierter Klassen wie StreamReader, SqlConnection und HttpClient.
Probier es selbst
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Verwenden Sie eine 'using'-Anweisung, um eine DatabaseConnection zu erstellen
// Innerhalb des using-Blocks:
// 1. Rufen Sie die Query-Methode mit der sqlQuery auf
// 2. Geben Sie das Ergebnis der Query-Methode aus
// Die Dispose-Methode wird automatisch aufgerufen, wenn der using-Block endet
}
}
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. EigenschaftenKonstruktorenObjekt-InitialisiererZusammenfassung - Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (:) SyntaxDas 'base'-SchlüsselwortVirtual & Override SchlüsselwörterVersiegelte KlassenDie 'object'-BasisklasseZusammenfassung – Mitarbeiter-Hierarchie7Fortgeschrittene Funktionen
OperatorüberladungIndexer (this[])ToString() überschreibenErweiterungsmethodenZusammenfassung - Benutzerdefinierte Liste2Eigenschaften & Statische Member
Automatisch implementierte EigenschaftenRead-Only- & Write-Only-EigenschaftenStatische Felder & MethodenStatische KlassenExpression-Bodied Member5Polymorphismus & Interfaces
Compile- vs. Runtime-PolymorphismusInterface vs. abstrakte KlasseMehrfache InterfacesExplizite InterfacesUpcasting & DowncastingRecap – Shape Calculator8Fortgeschrittene OOP-Konzepte
Komposition statt VererbungGenerics (Klassen & Methoden)Delegates und EventsAttribute und ReflectionIDisposable & using-AnweisungDependency Injection Grundlagen3Klassenarchitektur
Instanz- vs. statische Daten'readonly' & 'const' SchlüsselwörterBacking FieldsZusammenfassung - Bankkonto-Manager6Kapselung
ZugriffsmodifikatorenProperties zur KapselungImplementierung von Data HidingImmutability-MusterRückblick – Studierendendaten