Разумеется, вызов метода Finalize
GC.Collect. В предшествующих версиях .NET (но не в .NET Core) финализатор каждого объекта вызывался при окончании работы приложения. В .NET Core нет никаких способов принудительного запуска финализатора даже при завершении приложения.О чем бы ни говорили ваши инстинкты разработчика, подавляющее большинство классов C# не требует написания явной логики очистки или специального финализатора. Причина проста: если в классах используются лишь другие управляемые объекты, то все они в конечном итоге будут подвергнуты сборке мусора. Единственная ситуация, когда может возникнуть потребность спроектировать класс, способный выполнять после себя очистку, предусматривает работу с
В рамках платформы .NET Core неуправляемые ресурсы получаются путем прямого обращения к API-интерфейсу операционной системы с применением служб вызова платформы (Platform Invocation Services — P/Invoke) или в сложных сценариях взаимодействия с СОМ. С учетом сказанного можно сформулировать еще одно правило сборки мусора.
Правило.
Единственная серьезная причина для переопределения методаFinalize связана с использованием в классе C# неуправляемых ресурсов через P/Invoke или сложные задачи взаимодействия с СОМ (обычно посредством разнообразных членов типа System.Runtime.InteropServices.Marshal). Это объясняется тем, что в таких сценариях производится манипулирование памятью, которой исполняющая среда управлять не может.Переопределение метода System.Object.Finalize
В том редком случае, когда строится класс С#, в котором применяются неуправляемые ресурсы, вы вполне очевидно захотите обеспечить предсказуемое освобождение занимаемой памяти. В качестве примера создадим новый проект консольного приложения C# по имени SimpleFinalize
MyResourceWrapper, в котором используется неуправляемый ресурс (каким бы он ни был). Теперь необходимо переопределить метод Finalize. Как ни странно, для этого нельзя применять ключевое слово override языка С#:using System;
namespace SimpleFinalize
{
class MyResourceWrapper
{
// Compile-time error!
protected override void Finalize{ }
}
}
На самом деле для обеспечения того же самого эффекта используется синтаксис деструктора (подобный C++). Причина такой альтернативной формы переопределения виртуального метода заключается в том, что при обработке синтаксиса финализатора компилятор автоматически добавляет внутрь неявно переопределяемого метода Finalize
Финализаторы C# выглядят похожими на конструкторы тем, что именуются идентично классу, в котором определены. Вдобавок они снабжаются префиксом в виде тильды (~
MyResourceWrapper, который при вызове выдает звуковой сигнал. Очевидно, такой пример предназначен только для демонстрационных целей. В реальном приложении финализатор только освобождает любые неуправляемые ресурсы и не взаимодействует с другими управляемыми объектами, даже с теми, на которые ссылается текущий объект, т.к. нельзя предполагать, что они все еще существуют на момент вызова этого метода Finalize сборщиком мусора.using System;
// Переопределить System.Object.Finalize
// посредством синтаксиса финализатора.
class MyResourceWrapper
{
// Очистить неуправляемые ресурсы.
// Выдать звуковой сигнал при уничтожении
// (только в целях тестирования)
~MyResourceWrapper => Console.Beep;
}
Если теперь просмотреть код CIL данного финализатора с помощью утилиты ildasm.exe
Finalize помещены в блок try (см. главу 7). Связанный с ним блок finally гарантирует, что методы Finalize базовых классов будут всегда выполняться независимо от любых исключений, возникших в области try.Бьёрн Страуструп , Ирина Сергеевна Козлова , Бьерн Страуструп , Валерий Федорович Альмухаметов
Программирование, программы, базы данных / Базы данных / Программирование / Учебная и научная литература / Образование и наука / Книги по IT