Какой смысл переопределять Dispose (удаление bool) в .NET? - PullRequest
41 голосов
/ 25 февраля 2009

Если я напишу класс в C #, который реализует IDisposable, почему мне недостаточно просто реализовать

public void Dispose(){ ... } 

для освобождения любых неуправляемых ресурсов?

Есть

protected virtual void Dispose(bool disposing){ ... }

всегда необходимо, иногда необходимо, или что-то совсем другое?

Ответы [ 8 ]

43 голосов
/ 25 февраля 2009

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

Если у вас нет прямых дескрипторов на неуправляемых ресурсах (которые должны быть почти никогда ), вам не нужен финализатор.

Если вы запечатываете свой класс (и мои взгляды на классы запечатывания, где это возможно, вероятно, уже хорошо известны - дизайн для наследования или запрет его ) нет смысла вводить виртуальный метод.

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

public void Dispose()
{
    somethingElse.Dispose();
}

Стоит отметить, что если вы собираетесь получить действительно надежный код, вы должны убедиться, что вы ничего не пытаетесь сделать после того, как вас утилизировали, и выбросить ObjectDisposedException где уместно. Это хороший совет для библиотек классов, которые будут использоваться разработчиками по всему миру, но это очень большая работа, которая принесет очень мало пользы, если это будет просто класс, используемый в вашем собственном рабочем пространстве.

31 голосов
/ 25 февраля 2009

Это не строго необходимо. Это часть рекомендуемой одноразовой модели. Если вы еще не прочитали раздел Руководства по проектированию платформы (9.3 в первом издании, извините, во втором издании нет), тогда вам следует. Попробуйте эту ссылку .

Это полезно для различения одноразовой очистки и финализируемой уборки мусора.

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

14 голосов
/ 25 февраля 2009

В документах MSFT есть небольшая предвзятость по поводу одноразового шаблона. Есть две причины, по которым вы должны реализовать IDisposable:

  1. У вас есть поля типа, реализующего IDisposable
  2. У вас есть финализатор.

Случай 1 довольно распространен в большинстве кодов. Случай 2 довольно распространен в коде, который пишет Microsoft, именно они написали управляемые оболочки вокруг неуправляемых ресурсов, которые требуют доработки. Но должно быть очень редко в вашем коде. В конце концов, у вас есть все эти классы .NET, которые сделают за вас грязную работу. Вам просто нужно вызвать их методы Dispose ().

Только случай 2 требует одноразового использования. Microsoft должна использовать это много. Вам просто понадобится простой Dispose () большую часть времени.

5 голосов
/ 25 февраля 2009

В дополнение к другим замечательным ответам, вы можете проверить следующие статьи:

3 голосов
/ 25 февраля 2009

Дополнительный метод избавления от bool вышел где-то из руководства по проектированию каркаса. Это просто шаблон, позволяющий вашему классу иметь возможность вызывать метод dispose несколько раз, не вызывая исключения. Это не абсолютно необходимо. Технически вы можете сделать это в методе утилизации.

1 голос
/ 14 февраля 2017

Если класс реализует IDisposable.Dispose() и производный класс должен добавить дополнительную логику, этот класс должен предоставить какой-то метод Dispose, с которым производный класс может связываться. Поскольку некоторые классы могут реализовывать IDisposable.Dispose() без использования открытого метода Dispose(), полезно иметь виртуальный метод, который будет protected во всех реализациях IDisposable независимо от того, есть ли у них открытый метод Dispose или нет , В большинстве случаев аргумент bool на самом деле не имеет смысла, но его следует рассматривать как фиктивный аргумент, чтобы у protected virtual Dispose(bool) была подпись, отличная от подписи «может быть или не быть публичной» Dispose().

Классы, которые не используют protected virtual Dispose(bool), будут требовать, чтобы производные классы обрабатывали свою логику очистки способом, отличным от соглашения. Некоторые языки, такие как C ++ / CLI, которые оборудованы только для расширения реализаций IDisposable, которые следуют этому соглашению, могут быть не в состоянии извлечь классы из нестандартных реализаций.

1 голос
/ 08 февраля 2010

Одна вещь, которую он дает вам, - это возможность выполнять работу в Dispose (), не связанную с финализацией, и при этом очищать неуправляемые ресурсы.

Выполнение чего-либо с управляемым объектом, отличным от «себя» в финализаторе, крайне ... непредсказуемо. Большая часть этого происходит из-за того, что ваши финализаторы будут вызываться на этапе 2 выключения вашего AppDomain недетерминированным образом - поэтому, когда ваш финализатор вызывается, очень вероятно, что объекты, на которые у вас еще есть ссылки, уже были завершено.

Отправка вызовов Dispose и Finalizer на один и тот же метод позволяет вам совместно использовать код завершения работы, а логический параметр позволяет пропустить управляемую очистку, если она у вас есть.

Кроме того, виртуальность этого метода предоставляет наследникам простой способ добавить свой собственный код очистки с меньшим риском непреднамеренного не вызова вашего кода.

1 голос
/ 08 февраля 2010

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

Если вы пойдете по пути «сложного удаления» и реализуете финализатор, а затем забудете явным образом утилизировать ваш объект, ваш объект (и все, на что он ссылается) переживет дополнительное поколение GC, прежде чем он действительно будет удален (так как он должен еще раз подождать, пока CLR вызовет финализатор). Это просто вызывает большее давление памяти, которое вам не нужно. Кроме того, вызов финализатора для всей кучи объектов имеет нетривиальную стоимость.

Так что избегайте, если у вас (или ваших производных типов) нет неуправляемых ресурсов.

Да, и пока мы находимся в области: методы в вашем классе, которые обрабатывают события от других, должны быть «безопасными» перед лицом того, что их вызовут после удаления вашего класса. Проще всего просто выполнить no-op, если класс расположен. Смотри http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

...