IDisposable i instrukcja using
Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 45 z 70.
Niektóre obiekty przechowują zasoby, których garbage collector nie może automatycznie zwolnić — uchwyty plików, połączenia z bazą danych, gniazda sieciowe. Interfejs IDisposable zapewnia standardowy sposób zwalniania tych zasobów, gdy już ich nie potrzebujesz.
Klasa implementuje IDisposable, udostępniając metodę Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Możesz wywołać Dispose() ręcznie, ale co, jeśli wyjątek wystąpi, zanim dotrzesz do tej linii? Instrukcja using gwarantuje sprzątanie nawet wtedy, gdy coś pójdzie nie tak:
using (FileHandler handler = new FileHandler())
{
// Pracuj z obiektem handler
} // Dispose() jest tutaj wywoływana automatycznieNowoczesny C# oferuje czytelniejszą składnię dzięki deklaracji using, która zwalnia obiekt, gdy wykracza on poza zakres:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Pracuj z handler
} // Dispose() jest wywoływane przy zakończeniu metodyInstrukcja using działa z każdym typem implementującym IDisposable. Wbudowane klasy, takie jak StreamReader, SqlConnection i HttpClient, implementują ten interfejs, dzięki czemu prawidłowe zarządzanie zasobami jest proste i niezawodne.
Wyzwanie
ŁatwyZbudujmy symulator połączenia z bazą danych, który demonstruje prawidłowe zarządzanie zasobami za pomocą interfejsu IDisposable i instrukcji using. Utworzysz klasę, która śledzi, kiedy połączenia są otwierane i zamykane, zapewniając prawidłowe zwalnianie zasobów.
Rozmieścisz kod w dwóch plikach:
DatabaseConnection.cs: Utwórz klasęDatabaseConnectionw przestrzeni nazwDataAccess, która implementujeIDisposable. Twoje połączenie powinno:- Mieć właściwość
ConnectionName(string, tylko do odczytu), ustawianą przez konstruktor - Śledzić, czy połączenie zostało zwolnione, za pomocą prywatnego pola logicznego
- Wypisywać
Connection opened: {ConnectionName}podczas tworzenia obiektu (w konstruktorze) - Implementować metodę
Dispose(), która wypisujeConnection closed: {ConnectionName}— ale tylko wtedy, gdy zasób nie został jeszcze zwolniony (zapobieganie wielokrotnemu zwalnianiu) - Mieć metodę
Query(string sql), która zwracaExecuting on {ConnectionName}: {sql}
- Mieć właściwość
Program.cs: W pliku głównym zademonstruj prawidłowe zarządzanie zasobami, używając instrukcjiusingz połączeniem z bazą danych. Utwórz połączenie, wykonaj zapytanie i pozwól, aby blokusingautomatycznie zajął się sprzątaniem.
Otrzymasz dwa dane wejściowe:
- Nazwę połączenia (np.
MainDB) - Zapytanie SQL do wykonania (np.
SELECT * FROM Users)
Użyj instrukcji using, aby utworzyć połączenie. Wewnątrz bloku wywołaj metodę Query i wypisz jej wynik. Po zakończeniu bloku using metoda Dispose() zostanie wywołana automatycznie.
Na przykład, jeśli dane wejściowe to MainDB i SELECT * FROM Users, wynikiem powinno być:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBZauważ, że połączenie jest automatycznie zamykane po zakończeniu bloku using — nigdy nie musisz pamiętać o ręcznym wywołaniu Dispose(). Ten wzorzec zapewnia prawidłowe zwalnianie zasobów, nawet jeśli wewnątrz bloku wystąpi wyjątek!
Spróbuj swoich sił
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Użyj instrukcji 'using', aby utworzyć DatabaseConnection
// Wewnątrz bloku using:
// 1. Wywołaj metodę Query z argumentem sqlQuery
// 2. Wypisz wynik metody Query
// Metoda Dispose zostanie wywołana automatycznie po zakończeniu bloku using
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online