Должен ли я Dispose() DataSet и DataTable?

DataSet и DataTable реализуют IDisposable, поэтому, с помощью обычных передовых методов, я должен называть их методы Dispose().

Однако из того, что я читал до сих пор, DataSet и DataTable фактически не имеют неуправляемых ресурсов, поэтому Dispose() на самом деле не делает много.

Кроме того, я не могу просто использовать using(DataSet myDataSet...), потому что DataSet имеет коллекцию DataTables.

Итак, чтобы быть в безопасности, мне нужно будет перебирать через myDataSet.Tables, удалять каждый из DataTables, а затем утилизировать DataSet.

Итак, стоит ли хлопот вызывать Dispose() для всех моих DataSet и DataTables?

Добавление:

Для тех из вас, кто считает, что DataSet должен быть удален: В общем, шаблон для утилизации - использовать using или try..finally, потому что вы хотите гарантировать, что Dispose() будет вызван.

Тем не менее, это становится ужасно реальным для коллекции. Например, что вы делаете, если один из вызовов Dispose() выбрал исключение? Проглотите ли вы его (что "плохо" ), чтобы вы могли продолжать использовать следующий элемент?

Или вы предлагаете мне просто вызвать myDataSet.Dispose() и забыть об утилизации DataTables в myDataSet.Tables?

Ответ 1

Вот несколько обсуждений, объясняющих, почему Dispose не нужен для DataSet.

Утилизировать или не утилизировать?:

Метод Dispose в DataSet существует ТОЛЬКО из-за побочного эффекта наследования - другими словами, он фактически не делает ничего полезного в завершении.

Должен ли Dispose вызываться в объектах DataTable и DataSet? содержит некоторые объяснения от MVP:

Пространство имен system.data(ADONET) не содержит неуправляемые ресурсы. Поэтому нет необходимости распоряжаться ни одним из них, как если вы не добавили себе что-то особенное.

Понимание метода Dispose и наборов данных? имеет комментарий от авторитета Скотт Аллен:

В pratice мы редко Dispose DataSet, потому что он предлагает небольшую выгоду

Итак, консенсус в том, что в настоящее время нет веских оснований для вызова Dispose в DataSet.

Ответ 2

Обновление (1 декабря 2009 г.):

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

Исходный анализ делает применительно к объектам, требующим окончательной доработки, и точка, в которой методы не должны приниматься на поверхности без точного, глубокого понимания, все еще стоит.

Однако, оказывается, что DataSets, DataViews, DataTables подавляют завершение в своих конструкторах - вот почему вызов Dispose() на них явно ничего не делает.

Предположительно, это происходит потому, что у них нет неуправляемых ресурсов; поэтому, несмотря на то, что MarshalByValueComponent делает скидку для неуправляемых ресурсов, эти конкретные реализации не нуждаются и поэтому могут отказаться от финализации.

(Авторы .NET позаботятся о подавлении финализации тех типов, которые обычно занимают большую часть памяти, говорят о важности этой практики в целом для финализируемых типов.)

Несмотря на то, что эти детали все еще недостаточно документированы с момента создания .NET Framework (почти 8 лет назад), довольно удивительно (что вы, по сути, оставили свои собственные устройства, чтобы просеять хотя и противоречивый, двусмысленный материал, чтобы положить куски в то же время разочаровывает, но дает более полное представление о структуре, на которую мы полагаемся каждый день).

После многих чтений я понимаю свое понимание:

Если объект требует финализации, он может занимать память дольше, чем нужно, - почему: a) рассматривается любой тип, определяющий деструктор (или наследуемый от типа, который определяет деструктор) финализируемый; b) При распределении (до запуска конструктора) указатель помещается в очередь завершения; c) Конечный объект обычно требует 2 коллекций для возврата (вместо стандарта 1); d) Подавление финализации не удаляет объект из очереди финализации (как сообщает FinalizeQueue в SOS) Эта команда вводит в заблуждение; Знание того, какие объекты находятся в очереди финализации (само по себе), не является полезным; Знать, какие объекты находятся в очереди финализации и по-прежнему требовать завершения, было бы полезно (есть ли команда для этого?)

Подавление финализации в заголовке объекта немного отключается, указывая на время выполнения, которое не требуется для его запуска Finalizer (не нужно перемещать очередь FReachable); Он остается в очереди завершения (и продолжает сообщаться с помощью FinalizeQueue в SOS)

В классах DataTable, DataSet, DataView внедряется MarshalByValueComponent, конечный объект, который может (потенциально) обрабатывать неуправляемые ресурсы

  • Поскольку DataTable, DataSet, DataView не представляют неуправляемые ресурсы, они подавляют завершение в своих конструкторах.
  • Пока это необычный шаблон, он освобождает вызывающего абонента от необходимости беспокоиться о вызове Dispose после использования
  • Это и тот факт, что DataTables потенциально могут быть разделены между различными наборами данных, вероятно, почему DataSets не хочет удалять дочерние DataTables
  • Это также означает, что эти объекты будут отображаться в разделе "FinalizeQueue" в SOS
  • Однако эти объекты все равно должны быть возвращены после одной коллекции, например, их нефинитируемые копии

4 (новые ссылки):

Оригинальный ответ:

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

Без сомнения, Dispose должен быть вызван для любых объектов Finalizable.

Таблицы данных являются Finalizable.

Вызов Dispose значительно ускоряет восстановление памяти.

MarshalByValueComponent вызывает GC.SuppressFinalize(this) в своем Dispose() - пропуске это означает необходимость ждать десятков, если не сотни коллекций Gen0 до восстановления памяти:

При таком базовом понимании завершения мы уже может вывести некоторые очень важные вещи:

Во-первых, объекты, которые нуждаются в завершении живут дольше, чем объекты, которые этого не делают. На самом деле, они могут жить намного дольше. Например, предположим, что объект, который находится в gen2, необходимо доработать. Запланирование запланировано, но объект все еще находится в gen2, поэтому он будет не перечитываться до следующего gen2 коллекция бывает. Это может быть очень давно, и, по сути, если все будет хорошо, это будет долгое время, потому что коллекции gen2 являются дорогостоящими, и поэтому мы хотим, чтобы они происходят очень редко. Старшая объекты, нуждающиеся в завершении, могут придется ждать десятков, если не сотни коллекций gen0 до их пространство исправлено.

Во-вторых, объекты, нуждающиеся в доработке вызвать побочный ущерб. Поскольку внутренние указатели объектов должны оставаться действительные, не только объекты непосредственно требующая завершения финализации в памяти, но все объекты прямо или косвенно ссылается, также останется в памяти. Если огромный дерево объектов было закреплено отдельный объект, который требуется завершение, затем все дерево будет задержаться, возможно, надолго как мы только что обсуждали. это поэтому важно использовать финализаторы экономно и размещать их на объектах которые имеют как можно меньше внутреннего объекта как можно. В дереве пример, который я только что дал, вы можете легко избегайте проблемы, перемещая ресурсов, нуждающихся в отдельный объект и ссылка на этот объект в корне дерева. С этим скромным изменением только один объект (надеюсь, хороший небольшой объект), и затраты на окончательную доработку сводятся к минимуму.

Наконец, объекты, нуждающиеся в завершении создать работу для потока финализатора. Если ваш процесс финализации сложный, единственный и единственный поток финализатора будет тратить много времени, выполняющего эти шаги, что может вызвать отставание в работе и поэтому заставляют больше объектов задерживаться ожидая завершения. Следовательно, жизненно важно, чтобы финализаторы выполняют так же мало возможное. Помните также, что хотя все указатели объектов остаются в силе во время финализации это может быть случай, когда эти указатели приводят к объекты, которые уже были завершена и, следовательно, может быть меньше чем полезно. Это, как правило, безопаснее избегать указателей объектов в кода, даже если указатели действительны. Безопасный, короткий конечный код кода является лучшим.

Возьмите его у кого-то, кто видел 100-е МБ не связанных ссылок DataTables в Gen2: это чрезвычайно важно и полностью упущено ответами на эту тему.

Литература:

1 - http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 - http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

3 - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

Ответ 3

Вы должны предположить, что он делает что-то полезное и вызывает Dispose, даже если он ничего не делает в текущем состоянии .NET Framework, нет гарантии, что он останется таким образом в будущих версиях, что приведет к неэффективному использованию ресурсов.

Ответ 4

Даже если объект не имеет неуправляемых ресурсов, утилизация может помочь GC путем разбиения графиков объектов. В общем случае, если объект реализует IDisposable, тогда следует вызывать Dispose().

Действительно ли Dispose() делает что-то или нет, зависит от данного класса. В случае DataSet реализация Dispose() наследуется от MarshalByValueComponent. Он удаляется из контейнера и вызывает Disposed event. Исходный код ниже (дизассемблирован с помощью .NET Reflector):

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}

Ответ 5

Создаете ли вы сами DataTables? Поскольку итерация через дочерние объекты любого объекта (как в DataSet.Tables) обычно не требуется, так как это задание родителя для размещения всех его дочерних элементов.

Как правило, правило: если вы создали его, и он реализует IDisposable, Dispose it. Если вы НЕ создали его, то НЕ УДАЛЯЙТЕ его, что задание родительского объекта. Но у каждого объекта могут быть специальные правила, проверьте документацию.

Для .net 3.5 он явно говорит: "Утилизируйте его, когда вы больше не используете", чтобы я сделал.

Ответ 6

Я вызываю dispose в любое время, когда объект реализует IDisposeable. Это там по причине.

DataSets могут быть огромными ящиками памяти. Чем раньше они могут быть отмечены для очистки, тем лучше.

Обновление

Прошло 5 лет с тех пор, как я ответил на этот вопрос. Я до сих пор согласен с моим ответом. Если существует метод dispose, его следует вызывать, когда вы закончите с объектом. Интерфейс IDispose был реализован по какой-либо причине.

Ответ 7

Если ваше намерение или контекст этого вопроса действительно сбор мусора, то вы можете напрямую установить наборы данных и datatables null или использовать ключевое слово using и позволить им выйти из сферы действия. Dispose не делает много, как сказал Tetraneutron ранее. GC будет собирать объекты набора данных, на которые больше не ссылаются, а также те, которые недоступны.

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

Ответ 8

Наборы данных реализуют IDisposable полностью MarshalByValueComponent, который реализует IDisposable. Поскольку управляемые данные управляются, нет реальной выгоды для вызова dispose.

Ответ 9

Прежде всего, я бы проверил, что Dispose делает с DataSet. Возможно, использование рефлектора от redgate поможет.

Ответ 10

Попробуйте использовать функцию Clear(). Это отлично работает для меня для утилизации.

DataTable dt = GetDataSchema();
//populate dt, do whatever...
dt.Clear();