Home » Создание сайтов и программирование » Вызывать ли Dispose у DataSet

Вызывать ли Dispose у DataSet

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

Итак, если .NET класс не является оболочкой для неуправляемого ресурса (например, connection к базе данных, handle файла и т.п.), то программисту не надо заботиться о его уничтожении. Для этого предназначен сборщик мусора. Если же класс использует неуправляемые ресурсы, то необходим механизм их освобождения. Для этого предназначен интерфейс IDisposable и его метод Dispose. Этот метод следует вызывать для освобождение неуправляемых ресурсов. Кроме того, как правило, переопределяется метод Finalize (для C# это делается созданием метода с синтаксисом деструктора), в котором, также, происходит освобождения неуправляемых ресурсов на случай, если явно вызвать Dispose забыли. Явный вызов Dispose намного предпочтительнее, так как, во-первых, Finalize вызывается сборщиком мусора, который может начать работу через довольно длительное время, во-вторых, объекты, для которых вызывается Finalize, помещаются в специальную очередь завершения и существуют до следующей сборки мусора (т.е. занимают память дополнительное время). В методе Dispose, кроме освобождения неуправляемых ресурсов, вызывается GC.SuppressFinalize(), который сообщает сборщику мусора, что вызывать Finalize для этого объекта не надо.

Весь этот механизм очень подробно описан в книге Джефри Рихтера.

В принципе, если класс имплементирует IDisposable, то надо вызывать Dispose. Это однозначно для таких классов, как SqlConnection и SqlDataReader. Однако, насчет DataSet часто возникают вопросы.

Итак, DataSet имплементирует интерфейс IDisposable. Следовательно, правильно было бы вызывать метод Dispose при завершении работы с датасетом.

Для чего нужен Dispose? Для освобождения неуправляемых ресурсов. Память, занимаемая объектом, освобождается сборщиком мусора независимо от вызова Dispose. А какие неуправляемые ресурсы использует датасет? Никаких. Дело в том, что имплементация IDisposable достается ему в наследство от MarshalByValueComponent.

Что же делает Dispose в случае датасета? Вызывает GC.SuppressFinalize(), который сообщает сборщику мусора, что метод Finalize вызывать не надо. Больше ничего.

Значит, если мы не вызовем Dispose, ничего плохого не произойдет, т.к. никаких неуправляемых ресурсов освобождать не надо? Не совсем так. Дело в том, что тогда сборщик мусора вызовет метод Finalize и переместит объект в очередь завершения, что продлит время жизни объекта до следующей сборки мусора.

Получается, что сторонники вызова Dispose правы. Но давайте рассмотрим DataTable. Он, тоже, наследуется от MarshalByValueComponent. Если следовать нашей логике, необходимо вызывать Dispose и для каждого DataTable в DataSet. Я не знаю никого, кто так делает. А вы? Вызывать Dispose для DataSet и не вызывать для DataTable, как минимум, нелогично, т.к. объектов DataTable больше.

Что же делать? Вызывать или не вызывать? Не вызывать! Дело в том что в конструкторах DataSet и DataTable вызывается GC.SuppressFinalize() и, следовательно, сборщик мусора не будет вызывать Finalize!