Comments 24
Еще при чтении статьи у меня самого возник вопрос.
Логика третьего правила понятна — неуправляемые ресурсы должны быть по-любому освобождены, и если это не сделает программист с помощью Dispose, то в конце концов сборщик дернет финализатор.
А вот во втором правиле получается так, что если я Dispose забыл вызвать, то и ничего страшного?
Логика третьего правила понятна — неуправляемые ресурсы должны быть по-любому освобождены, и если это не сделает программист с помощью Dispose, то в конце концов сборщик дернет финализатор.
А вот во втором правиле получается так, что если я Dispose забыл вызвать, то и ничего страшного?
Ну когда сборщик мусора доберется до объекта он его таки вызовет, но иногда может быть поздно.
Если вы в классе открыли файл для эксклюзивного доступа, а потом забыли вызывать Dispose и закрыть файл, то код, кому файл может понадобиться (например, для удаления его), может работать крайне нестабильно. В какие-то моменты сборщик успеет отработать и все будет ОК, а в какие-то вы получите ошибку.
Поэтому лучше все же за Dispose не забывать, чтобы потом не лепить костыли вроде
GC.Collect()
Если вы в классе открыли файл для эксклюзивного доступа, а потом забыли вызывать Dispose и закрыть файл, то код, кому файл может понадобиться (например, для удаления его), может работать крайне нестабильно. В какие-то моменты сборщик успеет отработать и все будет ОК, а в какие-то вы получите ошибку.
Поэтому лучше все же за Dispose не забывать, чтобы потом не лепить костыли вроде
GC.Collect()
На GC надейся, а сам не плошай!
GC таки не вызывает Dispose. это работа программиста.
Да, действительно. Спасибо.
Но я везде где нужно реализую IDisposable и стараюсь использовать using. И как-то был в уверенности, что в принципе это не 100% обязательно, но в реальной жизни просто крайне желательно, чтобы не ловить странные ошибки доступа и прочее.
Но я везде где нужно реализую IDisposable и стараюсь использовать using. И как-то был в уверенности, что в принципе это не 100% обязательно, но в реальной жизни просто крайне желательно, чтобы не ловить странные ошибки доступа и прочее.
Очень даже страшно не вызывать Dispose :-)
Используйте конструкцию using (...) {....} она сама вызовет Dispose
Используйте конструкцию using (...) {....} она сама вызовет Dispose
Зависит от ситуации =) На самом деле, просто нет никакого другого способа кроме IDisposable (ну и документации) указать пользователю класса что он может 'течь', так что создателю класса ничего не остается.
Weak Event, теперь Dispose Pattern… интересно конечно, но имхо как-то поздно все это описывать.
«Это может вызвать исключение в потоке финализатора и нарушить работу всего приложения!»
Не понял, throwable в потоке финализатора рушит приложение? Это серьёзно так в .NET?
Не понял, throwable в потоке финализатора рушит приложение? Это серьёзно так в .NET?
IDisposable, кроме всего прочего, позволяет красиво организовывать работу с блоками кода.
Например следующий код:
Создаёт лог с таким содержимым:
Просто и красиво.
Другой вариант полезнюшки
В общем, идея, думаю понятна.
Кстати, если есть свои варианты использования — делитесь.
Например следующий код:
using (new Log()) { // ... if (Services[INotifier]==null) { Log.Warn("Notifier not set!"); return Log.Result(false); } else { // ... } }
Создаёт лог с таким содержимым:
{ 2010-03-12 16:39:06Z Engine.Notify() [..\src\Engine.cs:126] ! +0001 Notifier not set! = +0000 [Result]=[false] } 0,0002 s / +12 288,00 b
Просто и красиво.
Другой вариант полезнюшки
public class ForceCulture : IDisposable { public ForceCulture(CultureInfo culture) { //... } public ForceCulture() : this(CultureInfo.InvariantCulture) { } //... }
В общем, идея, думаю понятна.
Кстати, если есть свои варианты использования — делитесь.
Где-то в этом же блоге была фишка с WaitCursor. В конструкторе меняешь курсор на часы, в Dispose — обратно. И оборачиваешь блок кода, на котором пользователь должен подождать, в using c этим WaitCursor'ом. Идея, думаю, понятна.
Использую ProgressBlock в IDisposable.
Изначально с marquee style.
В процессе можно обновлять (и отменять):
IMHO лучше чем WaitCursor :)
Изначально с marquee style.
В процессе можно обновлять (и отменять):
///<summary> ///Update progress bar ///</summary> ///<param name='current'>Current progress value</param> ///<param name='total'>Total progress value</param> ///<returns><c>False</c> for user cancel.</returns> public bool UpdateProgress(long current, long total)
IMHO лучше чем WaitCursor :)
Огромное спасибо за статью, я как раз сейчас изучаю .NET и после вашей статьи наконец разобрался во всех Dispose(), финализаторах и прочем.
До сих пор представление о них у меня было весьма туманным)
До сих пор представление о них у меня было весьма туманным)
Могу посоветовать еще вот эти скринкасты на тему памяти:
www.red-gate.com/products/ants_memory_profiler/DOTNET_Memory_Management/Index.html
(ANTS Memory Profiler, кстати, совершенно потрясающий инструмент)
www.red-gate.com/products/ants_memory_profiler/DOTNET_Memory_Management/Index.html
(ANTS Memory Profiler, кстати, совершенно потрясающий инструмент)
Первое правило не совсем верное. При разработки библиотек имеет смысл у некоторых обектов реализовывать пустой Dispose, т.к. в будущем имплементация объекта может меняться, а несчатные пользователя билиотеки врядли сразу после выхода новой версии побегут менять свой код.Но это ИМХО.
Спасибо за статью.
А как насчет наследуемых классов? Если классы наследуются и в «среднем» появляется необходимость неуправляемого ресурса.
А как насчет наследуемых классов? Если классы наследуются и в «среднем» появляется необходимость неуправляемого ресурса.
В базовом классе:
В наследуемых классах переопределяем Dispose с параметром, в конце вызываем базовый:
public void Dispose()
{
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if (disposing)
{
...
}
...
}
* This source code was highlighted with Source Code Highlighter.
В наследуемых классах переопределяем Dispose с параметром, в конце вызываем базовый:
public override void Dispose(bool disposing)
{
if (disposing)
{
// освобождение своих ресурсов
}
base.Dispose(disposing);
}
* This source code was highlighted with Source Code Highlighter.
Sign up to leave a comment.
Как применять IDisposable и финализаторы: 3 простых правила