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 aufgerufenModernes 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 wirdDie 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.
Aufgabe
EinfachLass 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 KlasseDatabaseConnectionim NamespaceDataAccess, dieIDisposableimplementiert. 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, dieConnection closed: {ConnectionName}ausgibt – aber nur, wenn die Verbindung noch nicht verworfen wurde (um eine doppelte Freigabe zu verhindern) - Eine Methode
Query(string sql)besitzen, dieExecuting on {ConnectionName}: {sql}zurückgibt
- Eine Eigenschaft
Program.cs: Demonstriere in deiner Hauptdatei eine ordnungsgemäße Ressourcenverwaltung, indem du die Anweisungusingmit deiner Datenbankverbindung verwendest. Erstelle eine Verbindung, führe eine Abfrage aus und lasse denusing-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: MainDBBeachte, 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
}
}
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 – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition statt VererbungGenerics (Klassen & Methoden)Delegates und EventsAttribute und ReflectionIDisposable & using-AnweisungGrundlagen der Dependency Injection3Klassenarchitektur
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