ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
Шрифт:
Теперь, независимо от того, что может говорить вам интуиция разработчика, следует подчеркнуть, что большинству классов в C# не требуется никакой явной "уборки". Причина проста: если ваши типы используют другие управляемые объекты, то все, в конечном счете, будет обработано сборщиком мусора. Создавать класс, который должен заниматься "уборкой", вам придется только тогда, когда этот класс будет использовать неуправляемые ресурсы (например, прямой доступ к дескрипторам файлов ОС, неуправляемым базам данных или другим неуправляемым ресурсам). Вы, наверное, знаете, что неуправляемые ресурсы создаются в результате прямого вызова API
• Правило. Необходимость переопределения Finalize может возникать только тогда, когда класс C# использует неуправляемые ресурсы посредством PInvoke или при решении сложных задач взаимодействия с COM-объектами (обычно с применением типа System.Runtime.InteropServices.Marshal).
Замечание. В главе 3 уже отмечалось, что не допускается переопредешть Finalize с типами структуры. Теперь это совершенно ясно, поскольку структуры являются типами, характеризуемыми значениями, и они не размещаются в динамической памяти.
Переопределение System.Object.Finalize
В тех редких случаях, когда воздается C#-класс, использующий неуправляемые ресурсы, нужно гарантировать, что соответствующая память будет обрабатываться прогнозируемым образом. Предположим, что вы создали класс MyResourceWrapper, использующий неуправляемый ресурс (каким бы этот ресурс ни был), и вы хотите переопределить Finalize. Немного странно, но в C# вы не можете для этого использовать ключевое слово override.
Чтобы в пользовательском типе класса переопределить метод Finalize, вы должны использовать в C# другой синтаксис деструктора, напоминающий синтаксис деструктора в C++. Причина в том, что при обработке деструктора компилятором C# в метод Finalize автоматически добавляются необходимые элементы инфраструктуры (что будет продемонстрировано чуть позже).
Вот пример пользовательского деструктора для MyResourceWrapper, который при вызове генерирует системный сигнал. Ясно, что это сделано исключительно для примера. Настоящий деструктор должен только освобождать неуправляемые ресурсы, а не взаимодействовать с членами других управляемых o6ъeктов, поскольку вы не можете гарантировать, что эти объекты будут существовать в тот момент, когда сборщик мусора вызовет ваш метод Finalize.
Если рассмотреть этот деструктор с помощью ildasm.exe, вы увидите, что компилятор добавляет программный код контроля ошибок. Программный код вашего метода Finаlize
При тестировании типа MyResourceWrapper вы обнаружите, что завершение работы приложения сопровождается системным звуковым сигналом, поскольку среда CLR автоматически вызывает деструкторы объектов при освобождении доменов приложений.
Исходный код. Проект SimpleFinalize размещен в подкаталоге, соответствующем главе 5.
Детали процесса финализации
Чтобы не делать лишней работы, следует помнить о том, что целью метода Finalize является гарантия освобождения неуправляемых ресурсов .NET-объекта при сборке мусора. Поэтому при cоздании типа, не использующего неуправляемые элементы (а такая ситуация оказывается вполне типичней), от финализации будет мало пользы. На самом деле, при разработке своих типов вы должны избегать использования метода Finalize по той очень простой причине, что финализация требует времени.