Книга: C# для профессионалов. Том II

Деструкторы

Деструкторы

C# реализует отличную от C++ модель программирования деструкторов. Это связано с тем, что механизм сборки мусора в C# предполагает следующее:

? Существует меньшая необходимость в деструкторах, так как динамически распределенная память будет удаляться автоматически.

? Так как невозможно предсказать, когда сборщик мусора реально разрушит заданный объект, то если для класса предоставляется деструктор, невозможно предсказать в точности, когда этот деструктор будет выполнен.

Поскольку память очищается в C# "за сценой", то оказывается, что только небольшое число классов действительно нуждается в деструкторах. Для тех, кому это нужно (это классы, которые поддерживают внешние неуправляемые ресурсы, такие как соединения с файлами или с базами данных), C# имеет двухэтапный механизм разрушения:

1. Класс должен выводиться из интерфейса IDisposable и реализовывать метод Dispose(). Этот метод предназначен для явного вызова с помощью кода клиента для указания, что он закончил работать с объектом и требуется очистить ресурсы. (Интерфейсы будет рассмотрены позже в этом приложении.)

2. Класс должен отдельно реализовать деструктор, который рассматривается как запасной механизм, на случай, если клиент не вызывает Dispose().

Обычная реализация Dispose() выглядит следующим образом:

public void Dispose() {
 // очистка ресурсов
 System.GC.SuppressFinalize(this);
}
System.GC
является базовым классом, представляющим сборщика мусора. SuppressFinalize() является методом, который информирует сборщика мусора, что нет необходимости вызывать деструктор для разрушаемого объекта. Вызов SuppressFinalize() важен, так как имеется снижение производительности, если в объекте есть деструктор, который нужно вызывать в то время, когда сборщик мусора выполняет свою работу. Следствием этого является то, что реальное освобождение управляемой памяти, занимаемой этим объектом, будет существенно задерживаться.

Синтаксис деструктора по сути такой же в C#, как и в C++. Отметим, что в C# не требуется объявлять деструктор виртуальным, компилятор будет это подразумевать. Не требуется также предоставлять модификатор доступа:

Class MyClass {
 ~MyClass() {
  // очистка ресурсов
 }
}

Хотя метод Dispose() обычно явно вызывается клиентами, C# допускает альтернативный синтаксис, который гарантирует, что компилятор примет меры, чтобы он был вызван. Если переменная объявлена внутри блока using(), то ее область действия совпадает с блоком using и ее метод Dispose() будет вызываться при выходе из блока:

using (MyClass MyObject = new MyClass()) {
 // код
} // MyObject.Dispose() будет неявно вызван при выходе из этого блока

Отметим, что приведенный выше код будет компилироваться успешно только если MyClass выводится из интерфейса IDisposable и реализует метод Dispose(). Если нежелательно использовать синтаксис using, то можно опустить один или оба из двух шагов в последовательности деструктора (реализация Dispose() и реализация деструктора), но обычно реализуются оба шага. Можно также реализовать Dispose(), без привлечения интерфейса IDisposable, но если это делается, то снова невозможно использовать синтаксис using, чтобы для экземпляров этого класса Dispose() вызывался автоматически.

Оглавление книги


Генерация: 2.019. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз