Финализатор не вызывается

У меня есть класс на С#, где я хочу правильно закрыть некоторые коммуникационные порты, когда мой класс удаляется. Однако финализатор никогда не вызывается, когда я выхожу из программы. Это почему? Я делаю что-то неправильно?

Я вызываю удаление вручную, которое проходит и закрывает все коммуникации. Это тоже не стреляет.

Вот финализатор, который я использую:

~Power()
{
    Dispose(false);
}

person Spenduku    schedule 05.03.2011    source источник
comment
Я предполагаю, что ваша проблема не там, где вы думаете. Однако трудно сказать, не видя больше вашей программы.   -  person Gabe    schedule 05.03.2011


Ответы (4)


Финализатор (который вы используете здесь) вызывается только на этапе финализации, который произойдет во время GC.

Если вы правильно реализуете IDisposable, это никогда не должно вызываться. Я подробно рассказываю об этом в моей серии на IDisposable.

При этом, если ваши «коммуникационные порты» обрабатываются через управляемые классы, вам вообще не следует использовать финализатор. Это дополнительные накладные расходы, которые вам никак не помогут. Просто реализуйте IDisposable (правильно) и позвольте управляемым оболочкам вокруг классов портов выполнять финализацию, если это необходимо.

person Reed Copsey    schedule 05.03.2011
comment
Как правильно реализовать IDisposable? Мой класс наследует usercontrol. Я думал, что реализовал IDisposable? Понятно, что я могу ошибаться в этом. - person Spenduku; 05.03.2011
comment
@Spenduku: я бы порекомендовал прочитать мои статьи, ссылки на которые приведены выше. Я объясню это подробно, включая подклассы класса IDisposable. Какой класс вы используете для своих портов? - person Reed Copsey; 05.03.2011

Если дерево падает в лесу, и никто вокруг не слышит, издает ли оно звук? Убедитесь, что это так:

using System;

class Program {
    static void Main(string[] args) {
        new Test();
    }
}

class Test {
    ~Test() { Console.Beep(); }
}

Финализаторы любых объектов, оставшихся после завершения программы, вызываются непосредственно перед завершением процесса. Единственный способ избежать этого — грубо прервать процесс. Например, Environment.FailFast().

person Hans Passant    schedule 05.03.2011
comment
А что произойдет, если вы поместите новый Test() в другую статическую функцию, вызовете эту новую статическую функцию из Main и Application.Run(new Form1()) внутри Main? Я очень сомневаюсь, что GC завершит этот тестовый класс, пока вы не закроете приложение или не вызовете GC.Collect(); ;) - person SoLaR; 15.03.2018

Не гарантируется, что финализаторы C# будут вызываться в какое-либо конкретное время. Их не следует путать с деструкторами C++.

Если вы хотите гарантировать предсказуемую утилизацию, реализуйте IDispose и создайте экземпляр класса в блоке using:

using (Power power = new Power())
{
    //  blah blah
}

Если использование блока нецелесообразно, реализуйте IDispose — вам нужно написать метод Dispose, который избавляется от любых ресурсов, которые вам нужно освободить; для всех точных требований см. MSDN в Интернете - и вызовите Dispose() явно в соответствующее время. Если вы используете многопоточность, для этого может потребоваться некоторый код синхронизации, чтобы гарантировать, что это не произойдет слишком рано.

person 15ee8f99-57ff-4f92-890c-b56153    schedule 05.03.2011
comment
Я не могу использовать оператор using, так как создаю экземпляр класса при запуске своей программы. Затем вся внутренняя работа выполняется в отдельном потоке. - person Spenduku; 05.03.2011
comment
В этом случае ваша жизнь может оказаться не такой простой, как вам хотелось бы; см. выше. - person 15ee8f99-57ff-4f92-890c-b56153; 05.03.2011

Финализатор вызывается сборщиком мусора, а сборка мусора не является предсказуемым процессом, поэтому он не очень надежен. Вам нужно найти другие способы распоряжаться своими ресурсами.

person Bala R    schedule 05.03.2011
comment
C# не имеет деструкторов. Те вещи, которые используют синтаксис деструктора C++ -- это финализаторы. - person Ben Voigt; 05.03.2011
comment
ОП называл это деструктором и позже был отредактирован. - person Bala R; 05.03.2011
comment
@Ben Voigt: На самом деле, Руководство по программированию на C# называет их деструкторами: msdn.microsoft. com/en-us/library/66x5fx1b.aspx - person Jim Mischel; 05.03.2011
comment
@Ben: в C# они называются деструкторами, а в CLR — финализаторами. К сожалению, две команды выбрали разную терминологию; если бы нам пришлось делать это снова, мы, вероятно, попытались бы быть более последовательными. Но совершенно неправильно говорить, что в C# нет деструкторов. C# имеет деструкторы; спецификация называет их деструкторами, документация называет их деструкторами, и они реализуются путем переопределения финализатора. - person Eric Lippert; 05.03.2011
comment
@Eric: документация совершенно НЕПРАВИЛЬНАЯ. Говорит, что синтаксис деструктора в C# и C++ эквивалентен. Я' Мы уже отправили отзыв о документации. Я думаю, правильно будет сказать, что в C# синтаксис деструктора C++ используется для создания финализатора CLR. Это деструктор syntax, может быть, его даже можно назвать деструктором C#, но это не деструктор в общем смысле. Так что я буду продолжать призывать людей использовать слово finalizer, оно недвусмысленно и явно связано с finalizer в спецификациях C# и CLR. - person Ben Voigt; 05.03.2011
comment
@Ben: Я призываю вас сделать это, если это сделает вас счастливыми. Что касается документации, я предполагаю, что строка, которой вы расстроены, - это Предоставление неявного управления путем реализации защищенного Finalize для объекта (синтаксис деструктора в C# и C++). Хотя это предложение написано неуклюже и, вероятно, не соответствует грамматике, я не вижу в нем никакой ошибки, за исключением того факта, что в нем, вероятно, следовало сказать C++/CLI, а не просто C++. Я бы не стал использовать скобки; Я бы написал два предложения. - person Eric Lippert; 05.03.2011