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() вручную. Этот паттерн гарантирует, что ресурсы всегда будут очищены, даже если внутри блока возникнет исключение!
Попробуйте сами
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'Необязательные параметрыИменованные аргументыПерегрузка методов