Dispose vs Dispose (bool)
Я смущен насчет распоряжаться. Я пытаюсь правильно использовать ресурсы для моего кода. Поэтому я настраивал свои классы как IDisposable (с помощью метода Dispose), чтобы убедиться, что метод Dispose вызывается.
Но теперь FXCop сообщает мне много информации об Disposing = false и вызове Dispose (false).
Я не вижу метод Dispose, который принимает bool. Нужно ли мне это сделать? Если да, то почему? Почему бы просто не вызвать метод, вызываемый при его утилизации?
Я видел здесь код: http://msdn.microsoft.com/en-us/library/ms244737.aspx, который показывает, как сделать метод Disposing, который принимает bool. В нем говорится, что это для локальных управляемых ресурсов. Но я думал, что весь смысл распоряжения - только для неуправляемых ресурсов.
Кроме того, строка, которую FXCop жалуется, такова:
~OwnerDrawnPanel()
{
_font.Dispose();
}
В нем говорится:
CA1063: Microsoft.Design: измените 'OwnerDrawnPanel. ~ OwnerDrawnPanel()', чтобы он вызывал Dispose (false), а затем возвращался.
Но у Font нет Dispose (bool) на нем (что я могу найти).
Подводя итог:
Зачем мне нужен Dispose (bool)? и если да, то почему у Шрифта нет? и поскольку у него его нет, почему FXCop просит меня использовать его?
Спасибо за все замечательные ответы. Думаю, теперь я понимаю. Здесь
Ответ, как я вижу:
Устранение "неуправляемых" ресурсов относится к двум категориям:
- Ресурсы, которые обернуты в управляемый класс (например, Bitmap, Font и т.д.), но все равно нужно Dispose вызывать для их правильной очистки.
- Ресурсы, которые вы выделили, которые представляют собой собственные ресурсы (то есть контексты устройства, которые должны быть выпущены)
Dispose (bool) используется для определения разницы между двумя:
- Когда Dispose непосредственно вызывается на ваш объект, вы хотите освободить оба вида "неуправляемых" ресурсов.
- Когда ваш объект подходит для коллекции мусора, вам не нужно беспокоиться о первом виде ресурсов. Сборщик мусора позаботится о них, когда он очистит их. Вам нужно только беспокоиться о реальных ресурсах, которые вы выделили (если они есть).
Ответы
Ответ 1
IDisposable
предоставляет метод с сигнатурой
public void Dispose()
Рекомендации Microsoft (http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx) рекомендуют сделать второй закрытый метод с подписью
private void Dispose(bool)
Ваш общедоступный метод Dispose и Finalizer должен вызвать этот частный метод Dispose, чтобы предотвратить одновременное удаление управляемых ресурсов.
Вы можете исправить предупреждение, которое вы получаете, либо реализуя IDisposable, либо располагая свой объект шрифта в методе dispose, либо создавая метод Dispose(bool)
в своем классе, и сделайте ваш метод финализатора этим методом.
Ответ 2
Dispose(bool)
- это шаблон для реализации Finalize
и Dispose
для очистки неуправляемых ресурсов, см. это для деталей
Ответ 3
Dispose(bool)
не должен быть общедоступным, поэтому вы не видите его на Font
.
В случае, если какой-либо пользователь вашего класса забывает вызывать Dispose в своем методе, вы освободите неуправляемые ресурсы только путем вызова Dispose(false)
в Finalizer
.
В случае, если IDispose вызывается правильно, вы вызываете Dispose на управляемые ресурсы и также заботитесь о неуправляемом.
Флаг должен различать два случая.
Это шаблон, рекомендованный MSDN.
Ответ 4
FxCop говорит, что вы должны реализовать одноразовый шаблон, как описано здесь. Обратите внимание, что вы должны не использовать финализаторы для утилизации управляемых ресурсов, таких как _font
. Финализаторы используются для очистки неуправляемых ресурсов. Если вы не выполняете логику очистки в методе Dispose вашего (под) класса, они выполняются недетерминистически сборщиком мусора.
Ответ 5
Также обратите внимание, что очень редко, что вам нужно что-то делать в деструкторе. Регулярно все заботится сборщик мусора. Например, в вашем коде вам не нужно размещать объект _font
в деструкторе OwnerDrawnPanel
. Поскольку панель очищается GC, так будет _font
, потому что панель была единственной, кто ссылался на нее, правильно?
Как правило, если у вас есть одноразовые объекты, вам нужно их уничтожить только при вызове собственного метода Dispose
. Но НЕ в деструкторе. Когда ваш деструктор запущен, вы можете поспорить, что все ваши агрегированные объекты также очищаются.
Ответ 6
Вам почти не нужно использовать финализаторы. Они предназначены только для классов, которые непосредственно содержат неуправляемые ресурсы, а в .NET 2.0+ их следует обернуть в SafeHandle.
Ответ 7
Соглашаясь с Kumar, шаблон Dispose(bool disposing)
также документируется в MSDN. Различие заключается не в управляемых и неуправляемых ресурсах, а в том, вызывается ли Dispose
вашим кодом или временем выполнения.
Ответ 8
Я думаю, что Dispose(true)
освободит как управляемый, так и неуправляемый ресурс, так как нам не нужно снова вызывать завершение, потому что мы пишем GC.SupressFinalize()
после Dispose(true)
.
Мы вызываем Dispose(false)
в деструкторах для освобождения неуправляемых ресурсов и будем называть Runtime, а не код пользователя.
Ответ 9
Я нашел хорошую статью о правильной реализации интерфейса IDispose: http://msdn.microsoft.com/en-us/library/ms244737 (v = vs .80).aspx
Ответ 10
Схема реализации публичных финализаторов public void Dispose()
, protected virtual void Dispose(bool)
и ~ClassName()
является наилучшей практикой рекомендованной Microsoft в качестве способ аккуратно организовать ваш код очистки для управляемых и неуправляемых ресурсов.
В принципе, код, который использует ваш класс Disposable
, должен вызывать Dispose()
, но если это не так, finalizer ~ClassName()
будет вызван Garbage Collection, и на основе которого один из них будет использоваться, вы задайте аргумент Dispose(bool)
как true или false, а в Dispose(bool)
вы очищаете только управляемые ресурсы, если аргумент истинен.
Предупреждение, которое вы получаете, похоже, специально рекомендует использовать эту практику в вашем методе finalize ~ClassName()
.