Финализатор очень редко бывает полезен.Документация, на которую вы ссылаетесь, не совсем полезна - она предлагает следующие довольно круговые рекомендации:
Реализация Финализировать только на объектах, которые требуют финализации
Это отличный примерЗадавать вопрос, но это не очень полезно.
На практике в подавляющем большинстве случаев вам не нужен финализатор.(Одна из кривых обучения, которую должны пройти разработчики .NET, - это обнаружить, что в большинстве мест, где они думают, что им нужен финализатор, они этого не делают.) Вы пометили это как (среди прочего) вопрос WPF, иЯ бы сказал, что почти всегда было бы ошибкой помещать финализатор на объект пользовательского интерфейса.(Таким образом, даже если вы находитесь в одной из необычных ситуаций, в которых, как оказывается, требуется финализатор, эта работа не относится ни к какому коду, связанному с WPF.)
Для большинства сценариев, в которых финализаторы кажется как будто они могут быть полезны, они оказываются не полезными, потому что к тому времени, когда запускается ваш финализатор, уже слишком поздно, чтобы он мог что-то сделать полезное.
Например, обычно этоплохая идея пытаться что-либо делать с любым из объектов, на которые ссылается ваш объект, потому что к моменту запуска финализатора эти объекты уже могли быть завершены.(.NET не дает никаких гарантий относительно порядка запуска финализаторов, поэтому у вас просто нет возможности узнать, были ли завершены объекты, ссылки на которые у вас есть.) Это плохая идея - вызывать метод для объекта, у которого уже есть финализатор.был запущен.
Если у вас есть какой-то способ узнать, что какой-то объект определенно не был завершен, тогда его безопасно использовать, но это довольно необычная ситуация. (... если толькорассматриваемый объект не имеет финализатора и не использует сами финализируемые ресурсы, но в этом случае, вероятно, это не тот объект, с которым вам действительно нужно что-то делать, когда ваш собственный объект исчезает.)
Основная ситуация, в которой финализаторы кажутся полезными, это взаимодействие: например, предположим, что вы используете P / Invoke для вызова некоторого неуправляемого API, и этот API возвращает вам дескриптор.Возможно, есть какой-то другой API, который вам нужно вызвать, чтобы закрыть этот дескриптор.Поскольку это все неуправляемые вещи, .NET GC не знает, что это за дескрипторы, и ваша задача - убедиться, что они вычищены, и в этот момент финализатор является разумным ... за исключением практики, это почти всегда лучшеиспользовать SafeHandle
для этого сценария.
На практике единственными местами, где я использовал финализаторы, были а) эксперименты, предназначенные для исследования того, что делает ГХ, и б) диагностический код, предназначенный для обнаружениякое-что о том, как конкретные объекты используются в системе.Ни один из видов кода не должен заканчиваться вводом в производство.
Таким образом, ответ на вопрос, нужно ли вам "также использовать финализатор в дочернем классе": если вам нужно спросить, тогда ответ - нет.
Что касается дублирования флага ... другие ответы дают противоречивые советы здесь.Основные моменты: 1) вам нужно позвонить на базу Dispose
и 2) ваш Dispose
должен быть идемпотентом.(То есть, не имеет значения, вызывается ли он один, два, 5, 100 раз - он не должен жаловаться, если он вызывается более одного раза.) Вы можете реализовать это так, как вам нравится - логический флагодним способом, но я часто обнаруживал, что достаточно установить для некоторых полей значение null
в моем методе Dispose
, после чего устраняется необходимость в отдельном логическом флаге - вы можете сказать, что Dispose
уже был вызванпотому что вы уже установили эти поля на null
.
Многие рекомендации по IDisposable
крайне бесполезны, потому что они касаются ситуации, когда вам нужен финализатор, но на самом деле это очень необычный случай.Это означает, что многие люди пишут IDisposable
реализации, которые намного сложнее, чем необходимо.На практике большинство классов называют Стивеном Клири категорию "уровень 1" в статье, которую jpierson связал с .И для этого вам не нужны все вещи GC.KeepAlive
, GC.SuppressFinalize
и Dispose(bool)
, которые загромождают большинство примеров.Жизнь на самом деле намного проще в большинстве случаев, как показывает совет Клири для этих типов "уровня 1".