2010-01-06 2 views
1

Можно создать дубликат:
Should I Dispose() DataSet and DataTable?C# - Я знаю, я знаю, еще один вопрос об Dispose (больше связан с дизайном)!

OP комментарий: "Должен ли я Dispose() DataSet и DataTable" Я хотел бы сказать, что ссылка не является возможным решением. Это хорошая ссылка, но это больше связано с дизайном. Вместо этого игнорируйте, что открытое свойство является DataSet и заменяет его тем, что должно быть удалено. Там же будет применяться тот же вопрос.

Я возился с Crystal Reports, и у меня есть класс ReportData. Другими словами, этот класс инкапсулирует «заполнение» DataSet, который я буду использовать.

public class ReportData 
{ 
    private DataSet1 m_DS = null; // Notice this disposable member variable 

    public ReportData(... some parameters ...) 
    { 
     m_DS = new DataSet1(); 
     // Plus some other manipulation on m_DS 
    } 

    public DataSet1 GetDataSet 
    { 
     get 
     { 
      return m_DS; 
     } 
    } 

    // Everything else is pretty much private. 
    // This class is here to generate my DataSet 
} 

Вот как это будет использоваться какой-либо другой класс:

private void SetReportDataSource() 
{ 
    DataSet1 ds = m_RptData.GetDataSet; 
    m_Rpt.SetDataSource(ds); 
} 

Я довольно много обучения C# на лету (прочитать пару глав в интро книги, и просто пошел на нем, все по всему пути.). Из того, что я понимаю, если он реализует IDisposable, вы лучше уничтожаете его. DataSet реализует IDisposable, поэтому нам нужно утилизировать его.

Вот где дизайн часть приходит в:

Вопрос 1a: Должен ли я сделать мой ReportData класс IDisposable?

Другими словами, это выглядит, как я мог бы просто сделать это и сделать с ней:

private void SetReportDataSource() 
{ 
    using (DataSet1 ds = m_RptData.GetDataSet) 
    { 
     m_Rpt.SetDataSource(ds); 
    } 
} 

Вопрос 1b: Должен ли я быть более оборонительный каким-то образом?

Я не знаю, я думаю, я действительно пытаюсь обеспечить, чтобы он был утилизирован. Например, возьмем функцию SetReportDatsSource в качестве примера. Я использовал «использование», но кто-то другой может использовать класс и забыть добавить использование или вызвать Dispose в некотором роде. Поэтому я иду в мой класс ReportData:

public class ReportData : IDisposable 
{ 
    private DataSet1 m_DS = null; // Notice this disposable member variable 
    private bool m_IsDisposed = false; // This is new! 

    public ReportData(... some parameters ...) 
    { 
     m_DS = new DataSet1(); 
     // Plus some other manipulation on m_DS 
    } 

    // New code here (up until the GetDataSet property) 
    ~ReportData() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (m_IsDisposed == true) 
     { 
      return; 
     } 

     if (m_DS != null) 
     { 
      m_DS.Dispose(); 
      m_DS = null; 
     } 

     m_IsDisposed = true; 
    } 

    // Done with new code 

    public DataSet1 GetDataSet 
    { 
     get 
     { 
      return m_DS; 
     } 
    } 

    // Everything else is pretty much private. 
    // This class is here to generate my DataSet 
} 

Теперь давайте вернемся к классу вызывающему, у нас еще есть:

private void SetReportDataSource() 
{ 
    using (DataSet1 ds = m_RptData.GetDataSet) 
    { 
     m_Rpt.SetDataSource(ds); 
    } 
} 

Но я сделал ReportData (m_RptData) располагаемый сейчас тоже! Итак, мы захотим избавиться от этого! И потому, что это переменная-член (и я не могу просто использовать «с помощью» в том, как я использую его с SetReportDataSource), вы начинаете думать о том, чтобы этот призыв класс IDisposable, так что я могу иметь:

protected virtual void Dispose(bool disposing) 
    { 
     if (m_IsDisposed == true) 
     { 
      return; 
     } 

     if (m_ReportData != null) 
     { 
      m_ReportData.Dispose(); 
      m_ReportData = null; 
     } 

     m_IsDisposed = true; 
    } 

Итак, теперь этот класс имеет деструктор/финализатор и его общедоступный метод Dispose, распоряжающийся ReportData. Мы гарантируем, что мы избавимся от DataSet!

Но опять же, это приведет к вызову метода Dispose DataSet дважды. Поскольку функция SetReportDataSource предоставляет открытый DataSet, а класс ReportData также утилизирует одно и то же (и нет простого способа определить, удалил ли кто-нибудь из выставленного DataSet).

Кажется, орех.Мне кажется, что я:

a) Может быть, это переусердствует (или просто пытается быть действительно защитным, что хорошо)!

b) Возможно, вы прыгаете через кучу обручей.

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

Единственная проблема, которую я вижу с этим (и именно поэтому я отправил здесь):

В период между этой переменной член ReportData конкретизируется, и SetReportDataSource называется, какая-то ошибка/исключение может произойти. Таким образом, у нас никогда не будет возможности использовать «использование» (внутри SetReportDataSource) в нашем DataSet. Но этот набор данных был сконструирован с помощью ReportData (и мы хотим вызвать его на себя!)

Итак, теперь мы вернемся к созданию ReportData IDisposable, потому что нам понадобится хотя бы какая-то публичная функция «CleanUp». . ладно, я готов. :)

+0

Я хотел бы сказать, что «Должен ли я Dispose() DataSet и DataTable?» ссылка не является возможным решением. Это хорошая ссылка, но это больше связано с дизайном. Вместо этого игнорируйте, что открытое свойство является DataSet и заменяет его тем, что должно быть удалено. – JustLooking

+2

Кто-то проголосовал за то, чтобы закрыть это как «нагло оскорбительное»? Egad. – Beska

+0

Возможно, это связано с вашим аргументированным тоном и вашим смешным названием? Как насчет вашего неприлично длинного поста, который не составляет много? Как насчет отсутствия форматирования или смешных смайлов, которые вы используете в своем посте? Мне было бы интересно, почему кто-то ** не будет ** находить это наступление. – GEOCHET

ответ

0

Ответ 1A: Я бы рекомендовал использовать синтаксис, причина в том, что он является стандартом для обработки подобных вещей.

Ответ 1B: Если кто-то использует ваш класс, я предполагаю, что вы имеете в виду расширение, то разработчик должен обрабатывать любые изменения, которые он считает нужными.Согласно документам на Dispose()

Если метод Dispose объекта вызывается более одного раза, объект должен игнорировать все вызовы после первого. Объект не должен генерировать исключение, если его метод Dispose вызывается несколько раз. Dispose может генерировать исключение, если возникает ошибка, поскольку ресурс уже освобожден, а Dispose не был вызван ранее. (http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28VS.71%29.aspx)

Сборщик мусора в какой-то момент схватит ваш объект и обработает его. Запрет катастрофы.

+0

Точка ответа (я боюсь, что мне, возможно, придется повторно опубликовать этот вопрос, используя что-то другое, кроме DataSet). Что касается 1B, я не имел в виду расширение. Я имел в виду вызывающий класс, создающий экземпляр ReportData, а затем позже его использование (одна из проблем, на мой взгляд, была создание экземпляра ... исключение/ошибка, прежде чем я когда-либо смогу использовать это использование). – JustLooking

+1

Ну, в этом случае исключение произошло бы, и это не имеет значения. GC должен ее удержать, поскольку нет доступных доступных ссылок. – Woot4Moo

+0

(Еще один вопрос для ответа). В действительности, я имею в виду: ReportData получает экземпляр (таким образом, DataSet делает - DataSet является одноразовым). Все в порядке. Позже, в каком-то другом случае, возникает ошибка. Из-за этой ошибки мы никогда не вызываем SetReportDataSource. Теперь нам нужно избавиться от ReportData/DataSet. Я не говорю об исключении во время фактического создания. Мы полагаемся только на использование «use» в SetDataSource (чтобы избавиться от DataSet), но если в какой-то момент произошла ошибка между завершенным экземпляром и SetDataSource, то что? – JustLooking

3

Пожалуйста, см: Should I Dispose() DataSet and DataTable?

Как придумать несколько раз на SO, если объект он реализует IDisposable, то вы должны вызвать Dispose(). [В среде .NET есть несколько мест, где оригинальные дизайнеры, по-видимому, должны были бы использовать Dispose(), но затем не нуждались в ней. Но самым безопасным и правильным было бы назвать Dispose независимо.]

+0

Это полезная ссылка, спасибо. Но давайте проигнорируем тот факт, что это DataSet. Это может быть что-то еще, я не знаю, Шрифт (который я раскрыл). Такое же обсуждение будет иметь место. По общему признанию, я вхожу в режим: если у него есть метод Dispose, я хочу его назвать. В отличие от: у него есть метод Dispose, позвольте мне google мир, чтобы увидеть, действительно ли это что-то делает. И теперь мне нужно немного улучшить и выяснить, как эти люди отлаживаются в исходном коде C#, чтобы определить, что Dispose действительно бесполезен ... и ... уф! Но спасибо, хорошая ссылка. И +1 для вас. – JustLooking

1

Вы не указали код для SetDataSource, но этот фрагмент кода будет работать, только если SetDataSource сразу же уничтожает содержимое DataSet и делает не хранить ссылку на него:

private void SetReportDataSource() 
{ 
    using (DataSet1 ds = m_RptData.GetDataSet) 
    { 
     m_Rpt.SetDataSource(ds); 
    } 
} 

что касается остальной части коды и вопроса (цитирует удаленный ответ):


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

void Dispose() { 
    if (m_DS != null) m_DS.Dispose() 
} 

Общее правило для Финализаторы: Когда сомневаетесь, нет.
Вам понадобится только один, когда вы используете неподходящий ресурс.

4

Если вы держите что-то, что реализует IDisposable, простейший шаблон должен реализовать IDisposable самостоятельно и вызвать методы Dispose во всех ваших IDisposables. Быть более защитным, чем кажется невозможным; если кто-то, использующий ваш класс , забудет, чтобы вызвать метод Dispose, то как вы узнали, что они сделаны с вами?

Редактировать: Во-вторых, вызов Finalize говорит вам, что ваш клиент сделан с вами; у них больше нет ссылок на вас ...