Статический финализатор

Как правильно выполнить статическую финализацию?

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


person Michael Damatov    schedule 01.11.2008    source источник
comment
Во-первых, в C# нам нужно отказаться от взаимозаменяемого использования финализатора и деструктора. Один детерминирован, другой нет. Интересно отметить, что спецификация C# получает термины обратно из CLR и других спецификаций языка .NET. Также интересно отметить, что в примечаниях комитета по языку C# прямо говорится, что не существует предвиденных причин, по которым C# не может иметь статических финализаторов. stackoverflow.com/a/1875149/56793   -  person JMD    schedule 26.09.2014


Ответы (5)


В принципе, вы не можете. Создайте свой путь вокруг него в максимально возможной степени.

Не забывайте, что программа всегда может внезапно завершиться в любом случае — очевидный пример — кто-то отключил питание. Так что все, что вы делаете, должно быть сделано с максимальной отдачей. В этом случае я надеюсь, что AppDomain.ProcessExit будет достаточно.

Что нужно сделать в вашем конкретном случае?

person Jon Skeet    schedule 01.11.2008
comment
Как этот ответ связан с ответом Майкла (поскольку кажется, что статические финализаторы могут быть)? (В любом случае я согласен, что финализаторы ненадежны.) - person mafu; 29.02.2012
comment
@mafutrct: ответ Майкла на самом деле не является статическим финализатором. Это статическое поле со ссылкой на экземпляр с финализатором. Это не одно и то же, хотя последствия могут быть схожими. Я бы не использовал его лично. - person Jon Skeet; 29.02.2012
comment
Истинная ценность статического финализатора - с точки зрения разработчика Delphi, где такие вещи поддерживаются на уровне языка - не какая-то бессмысленная гарантия того, что это будет работать (как вы указываете, кто-то всегда может отключить ,), а скорее гарантия того, что он запустится, когда класс выйдет за пределы области видимости. Если сборка, содержащая класс, была загружена динамически как подключаемый модуль и выгружается перед завершением программы, это может быть довольно существенное различие, и наличие подпрограммы очистки, которая запускается при выходе из процесса, не годится. Как правильно справиться с этим сценарием? - person Mason Wheeler; 01.01.2015
comment
@MasonWheeler: Обычно у вас есть плагин в собственном AppDomain, и в этом случае вы можете подписаться на событие AppDomain.DomainUnload. (Нет такого понятия, как класс, выходящий за рамки, поскольку класс не находится в области видимости с самого начала.) - person Jon Skeet; 01.01.2015

Герфрид Вагнер написал прекрасную статью, объясняющую, как это реализовать — увы, на немецком языке ( и ВБ). Тем не менее, код должен быть понятным.

Я пробовал:

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. три секунды...

person Michael Damatov    schedule 01.11.2008
comment
Это лучший ответ, так как вы можете отлаживать свой финализатор таким образом, тогда как делегат AppDomain.ProcessExit не позволяет вам отлаживать его (по крайней мере, по моему опыту). - person Tod Thomson; 10.09.2013

Два решения, которые приходят на ум:

  • Не используйте статический класс. Если вы используете нестатический класс и создаете его экземпляр, вам не нужно так сильно беспокоиться об очистке.
  • Если это не вариант, я бы сказал, что это хорошая ситуация для использования синглтона. Это создаст копию вашего объекта и вызовет финализатор при выходе, но по-прежнему позволит вам рассматривать его как статический класс по большей части. В конце концов, ваш класс уже статичен и, следовательно, разделяет большинство распространенных причин не использовать синглтон.
person Jason Baker    schedule 01.11.2008

Я бы спросил, что вы загружаете в свои статические методы, которые необходимо освободить. Я, конечно, не рекомендовал бы делать это в статическом методе.

Тем не менее, ваш статический метод может создать экземпляр объекта, имеющего метод finalize.

person Ady    schedule 01.11.2008

Портировать ответ Майкла Даматова (C#), основанный на Herfried K. Wagner. (VB.NET) вот версия С++/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 является универсальным (шаблонным), предположение о том, что его статический конструктор и статический деструктор будут вызываться не более одного раза за выполнение приложения, более недействительно.

person ILIA BROUDNO    schedule 31.07.2014