Menu
Coddy logo textTech

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, реализуют этот интерфейс, что делает правильное управление ресурсами простым и надежным.

challenge icon

Задание

Легко

Давайте создадим симулятор подключения к базе данных, который демонстрирует правильное управление ресурсами с использованием интерфейса 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
        
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование