Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
public class Object
{
...
protected virtual void Finalize() {}
}
За счет переопределения метода
Finalize()
Finalize()
Finalize()
На заметку! Переопределять метод
Finalize()
iDisposable
ref
ref
Dispose()
Разумеется, вызов метода
Finalize()
GC.Collect()
О чем бы ни говорили ваши инстинкты разработчика, подавляющее большинство классов C# не требует написания явной логики очистки или специального финализатора. Причина проста: если в классах используются лишь другие управляемые объекты, то все они в конечном итоге будут подвергнуты сборке мусора. Единственная ситуация, когда может возникнуть потребность спроектировать класс, способный выполнять после себя очистку, предусматривает работу с неуправляемыми ресурсами (такими как низкоуровневые файловые дескрипторы операционной системы, низкоуровневые неуправляемые подключения к базам данных, фрагменты неуправляемой памяти и т.д.).
В рамках платформы .NET Core неуправляемые ресурсы получаются путем прямого обращения к API-интерфейсу операционной системы с применением служб вызова платформы (Platform Invocation Services — P/Invoke) или в сложных сценариях взаимодействия с СОМ. С учетом сказанного можно сформулировать еще одно правило сборки мусора.
Правило. Единственная серьезная причина для переопределения метода
Finalize()
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
finally
Finalize()
try