IDisposable и оператор using
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 45 из 70.
Некоторые объекты удерживают ресурсы, которые сборщик мусора не может очистить автоматически — дескрипторы файлов, подключения к базам данных, сетевые сокеты. Интерфейс IDisposable предоставляет стандартный способ освобождения этих ресурсов, когда вы закончите с ними работать.
Класс реализует IDisposable путем предоставления метода Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Вы могли бы вызвать Dispose() вручную, но что если исключение возникнет до того, как вы дойдете до этой строки? Оператор using гарантирует выполнение очистки, даже если что-то пойдет не так:
using (FileHandler handler = new FileHandler())
{
// Работа с обработчиком
} // Dispose() вызывается здесь автоматическиСовременный C# предлагает более чистый синтаксис с объявлением using, которое освобождает объект, когда он выходит из области видимости:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Работа с handler
} // Dispose() вызывается при выходе из методаОператор using работает с любым типом, который реализует IDisposable. Встроенные классы, такие как StreamReader, SqlConnection и HttpClient, реализуют этот интерфейс, что делает правильное управление ресурсами простым и надежным.
Задание
ЛегкоДавайте создадим симулятор подключения к базе данных, который демонстрирует правильное управление ресурсами с использованием интерфейса IDisposable и оператора using. Вы создадите класс, который отслеживает открытие и закрытие соединений, гарантируя, что ресурсы всегда освобождаются должным образом.
Вы организуете свой код в двух файлах:
DatabaseConnection.cs: Создайте классDatabaseConnectionв пространстве именDataAccess, который реализует интерфейсIDisposable. Ваше соединение должно:- Иметь свойство
ConnectionName(строка, только для чтения), устанавливаемое через конструктор - Отслеживать, было ли соединение освобождено, используя закрытое логическое поле
- Выводить
Connection opened: {ConnectionName}при создании объекта (в конструкторе) - Реализовать метод
Dispose()для выводаConnection closed: {ConnectionName}— но только если объект еще не был освобожден (предотвращение двойного освобождения) - Иметь метод
Query(string sql), который возвращаетExecuting on {ConnectionName}: {sql}
- Иметь свойство
Program.cs: В основном файле продемонстрируйте правильное управление ресурсами, используя операторusingс вашим подключением к базе данных. Создайте соединение, выполните запрос и позвольте блокуusingавтоматически обработать очистку.
Вы получите два входных значения:
- Имя соединения (например,
MainDB) - SQL-запрос для выполнения (например,
SELECT * FROM Users)
Используйте оператор using для создания соединения. Внутри блока вызовите метод Query и выведите его результат. Когда блок using завершится, метод Dispose() будет вызван автоматически.
Например, если входные данные — MainDB и SELECT * FROM Users, вывод должен быть следующим:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBОбратите внимание, как соединение автоматически закрывается при завершении блока using — вам никогда не придется вызывать Dispose() вручную. Этот паттерн гарантирует, что ресурсы всегда будут очищены, даже если внутри блока возникнет исключение!
Шпаргалка
Интерфейс IDisposable предоставляет стандартный способ освобождения ресурсов, которые сборщик мусора не может очистить автоматически (дескрипторы файлов, подключения к базе данных, сетевые сокеты).
Класс реализует IDisposable, предоставляя метод Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Оператор using гарантирует автоматическое выполнение очистки, даже если возникают исключения:
using (FileHandler handler = new FileHandler())
{
// Работа с обработчиком
} // Dispose() вызывается здесь автоматическиСовременный C# предлагает более чистый синтаксис с объявлением using:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Работа с обработчиком
} // Dispose() вызывается при выходе из методаОператор using работает с любым типом, реализующим IDisposable, включая встроенные классы, такие как StreamReader, SqlConnection и HttpClient.
Попробуйте сами
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Используйте оператор 'using' для создания DatabaseConnection
// Внутри блока using:
// 1. Вызовите метод Query с sqlQuery
// 2. Выведите результат метода Query
// Метод Dispose будет вызван автоматически по завершении блока using
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методов