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

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

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

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

JMD 26.09.2014 18:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
45
1
15 682
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

В принципе, вы не можете. Разработайте свой способ обойти это как можно более полно.

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

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

Как этот ответ соотносится с ответом Майкла (поскольку кажется, что можно использовать статические финализаторы)? (В любом случае я согласен с тем, что финализаторы ненадежны.)

mafu 29.02.2012 20:02

@mafutrct: Ответ Майкла на самом деле не статический финализатор. Это статическое поле со ссылкой на экземпляр, у которого есть финализатор. Это не одно и то же, хотя и может иметь похожие эффекты. Я бы не стал использовать это лично.

Jon Skeet 29.02.2012 20:04

Истинная ценность статического финализатора - с точки зрения разработчика Delphi, где такие вещи поддерживаются на уровне языка, - не какая-то бессмысленная «гарантия того, что это будет работать» (как вы указываете, кто-то всегда может вытащить плагин), а скорее гарантия того, что он будет запущен, когда класс выйдет за пределы области видимости. Если сборка, содержащая класс, была загружена динамически как плагин и выгружается перед завершением программы, это может быть довольно значительным различием, и наличие подпрограммы очистки, которая запускается при выходе из процесса, не является хорошо. Как вы «правильно» справитесь с этим сценарием?

Mason Wheeler 01.01.2015 03:01

@MasonWheeler: Обычно у вас есть плагин в собственном домене приложений, и в этом случае вы можете подписаться на событие AppDomain.DomainUnload. (Нет такой концепции, как выход класса «за пределы области видимости», поскольку класс не входит в область видимости для начала.)

Jon Skeet 01.01.2015 11:16

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

Тем не менее, ваш статический метод может создать экземпляр объекта, у которого есть метод 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 не позволяет вам отлаживать его (по крайней мере, по моему опыту).

Tod Thomson 10.09.2013 04:34

Перенести ответ Михаила Даматова (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 является универсальным (шаблонным), предположение о том, что его статический конструктор и статический деструктор будут вызываться не более одного раза за выполнение приложения, больше не действует.

Другие вопросы по теме