Язык программирования C#9 и платформа .NET5. Страница 192
{ ... .try { ... } // end .try finally { IL_0018: callvirt instance void [System.Runtime]System.IDisposable::Dispose() ... } // end handler IL_001f: ret} // end of method Program::UsingDeclarationПо сути, это новое средство является "магией" компилятора, позволяющей сэкономить несколько нажатий клавиш. При его использовании соблюдайте осторожность, т.к. новый синтаксис не настолько ясен, как предыдущий.
Создание финализируемых и освобождаемых типов
К настоящему моменту вы видели два разных подхода к конструированию класса, который очищает внутренние неуправляемые ресурсы. С одной стороны, можно применять финализатор. Использование такого подхода дает уверенность в том, что объект будет очищать себя сам во время сборки мусора (когда бы она ни произошла) без вмешательства со стороны пользователя. С другой стороны, можно реализовать интерфейс
IDisposableDispose()Нетрудно догадаться, что в одном определении класса можно смешивать оба подхода, извлекая лучшее из обеих моделей. Если пользователь объекта не забыл вызвать метод
Dispose()GC.SuppressFinalize()Dispose()Ниже представлена очередная версия класса
MyResourceWrapperFinalizableDisposableClassusing System;namespace FinalizableDisposableClass{ // Усовершенствованная оболочка для ресурсов. public class MyResourceWrapper : IDisposable { // Сборщик мусора будет вызывать этот метод, если // пользователь объекта забыл вызвать Dispose(). ~MyResourceWrapper() { // Очистить любые внутренние неуправляемые ресурсы. // **Не** вызывать Dispose() на управляемых объектах. } // Пользователь объекта будет вызывать этот метод // для как можно более скорой очистки ресурсов. public void Dispose() { // Очистить неуправляемые ресурсы. // Вызвать Dispose() для других освобождаемых объектов, // содержащихся внутри. // Если пользователь вызвал Dispose(), то финализация // не нужна, поэтому подавить ее. GC.SuppressFinalize(this); } }}Обратите внимание, что метод
Dispose()GC.SuppressFinalize()Dispose()Формализованный шаблон освобождения
Текущая реализация класса
MyResourceWrapperFinalize()Dispose()Во-вторых, желательно удостовериться в том, что метод
Finalize()Dispose()Dispose()Dispose()Для решения таких проектных задач в Microsoft определили формальный шаблон освобождения, который соблюдает баланс между надежностью, удобством сопровождения и производительностью. Вот окончательная версия класса
MyResourceWrapperclass MyResourceWrapper : IDisposable{ // Используется для выяснения, вызывался ли метод Dispose(). private bool disposed = false; public void Dispose() { // Вызвать вспомогательный метод. // Указание true означает, что очистку // запустил пользователь объекта. CleanUp(true); // Подавить финализацию. GC.SuppressFinalize(this); }