Как правильно выполнить статическую финализацию?
Статического деструктора нет. Событие AppDomain.DomainUnload не возникает в домене по умолчанию. Событие AppDomain.ProcessExit разделяет общее время трех секунд (настройки по умолчанию) между всеми обработчиками событий, поэтому его нельзя использовать на самом деле.





В принципе, вы не можете. Разработайте свой способ обойти это как можно более полно.
Не забывайте, что программа в любом случае может внезапно завершить работу всегда - очевидным примером является отключение питания. Так что все, что вы делаете, должно быть «максимальным усилием» - в этом случае я бы определенно надеяться, что AppDomain.ProcessExit был бы достаточно хорош.
Что вам нужно делать в вашем конкретном случае?
Как этот ответ соотносится с ответом Майкла (поскольку кажется, что можно использовать статические финализаторы)? (В любом случае я согласен с тем, что финализаторы ненадежны.)
@mafutrct: Ответ Майкла на самом деле не статический финализатор. Это статическое поле со ссылкой на экземпляр, у которого есть финализатор. Это не одно и то же, хотя и может иметь похожие эффекты. Я бы не стал использовать это лично.
Истинная ценность статического финализатора - с точки зрения разработчика Delphi, где такие вещи поддерживаются на уровне языка, - не какая-то бессмысленная «гарантия того, что это будет работать» (как вы указываете, кто-то всегда может вытащить плагин), а скорее гарантия того, что он будет запущен, когда класс выйдет за пределы области видимости. Если сборка, содержащая класс, была загружена динамически как плагин и выгружается перед завершением программы, это может быть довольно значительным различием, и наличие подпрограммы очистки, которая запускается при выходе из процесса, не является хорошо. Как вы «правильно» справитесь с этим сценарием?
@MasonWheeler: Обычно у вас есть плагин в собственном домене приложений, и в этом случае вы можете подписаться на событие AppDomain.DomainUnload. (Нет такой концепции, как выход класса «за пределы области видимости», поскольку класс не входит в область видимости для начала.)
Я бы спросил, что вы загружаете в свои статические методы, которые необходимо выпустить. Я бы определенно не рекомендовал делать это статическим методом.
Тем не менее, ваш статический метод может создать экземпляр объекта, у которого есть метод finalize.
На ум приходят два решения:
Herfried Wagner has written an excellent article explaining how to implement this – alas, in German (and VB). Still, the code should be understandable.
Я пробовал:
static readonly Finalizer finalizer = new Finalizer();
sealed class Finalizer {
~Finalizer() {
Thread.Sleep(1000);
Console.WriteLine("one");
Thread.Sleep(1000);
Console.WriteLine("two");
Thread.Sleep(1000);
Console.WriteLine("three");
Thread.Sleep(1000);
Console.WriteLine("four");
Thread.Sleep(1000);
Console.WriteLine("five");
}
}
Кажется, это работает точно так же, как событие AppDomain.ProcessExit: финализатор получает ca. три секунды ...
Это лучший ответ, поскольку вы можете отлаживать «финализатор» таким образом, тогда как делегат AppDomain.ProcessExit не позволяет вам отлаживать его (по крайней мере, по моему опыту).
Перенести ответ Михаила Даматова (C#), основанный на Херфриде К. Вагнере. (VB.NET) вот версия C++ / CLI:
ref class MyClass
{
ref class StaticFinalizer sealed
{
!StaticFinalizer();
};
static initonly StaticFinalizer^ stDestr = gcnew StaticFinalizer();
}
MyClass::StaticFinalizer::!StaticFinalizer()
{
System::Diagnostics::Debug::WriteLine("In StaticFinalizer!");
}
P.S. Как и метод AppDomain.ProcessExit, этот метод не может быть вызван, если процесс завершается ненормально (например, из диспетчера задач). Еще одно предостережение: если MyClass является универсальным (шаблонным), предположение о том, что его статический конструктор и статический деструктор будут вызываться не более одного раза за выполнение приложения, больше не действует.
Во-первых, в C# нам нужно избавиться от привычки использовать финализатор и деструктор поочередно. Один детерминирован, другой - нет. Интересно отметить, что спецификация C# получает термины в обратном направлении от CLR и других спецификаций языка .NET. Также интересно отметить, что в примечаниях комитета по языку C# прямо говорится, что нет никаких предвиденных причин, по которым C# не может иметь статические финализаторы. stackoverflow.com/a/1875149/56793