Я должен реализовать IDisposable здесь?

Мой метод, который называет возвраты SQL Server a DataReader но из-за того, что я должен сделать - который является возвратом DataReader к вызывающему методу, который находится в коде страницы - позади - я не могу закрыть соединение в классе метода, который называет SQL-сервер. Из-за этого, я имею не наконец или блоки использования.

Корректный способ расположить ресурсы для создания реализации класса IDisposable? Кроме того, я должен явно расположить неуправляемый ресурс (поля уровня класса) от вызывающей стороны?

Править: Я передаю datareader обратно, потому что я должен связать определенные данные от datareader до управления listitem, таким образом, в классе вызова (страница Codebehind), я делаю:

 new ListItem(datareader["dc"]); (along those lines).
7
задан GurdeepS 19 May 2010 в 21:01
поделиться

7 ответов

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

Однако при этом возникает вопрос к вашей архитектуре. Почему вы хотите отправить на страницу сам DataReader , а не вызывать метод, который сделает это за вас (включая соответствующую очистку), возвращая то, что необходимо? Если необходимо выдать на страницу реального читателя, пусть так и будет.

7
ответ дан 6 December 2019 в 08:14
поделиться

Да, вы должны реализовать IDisposable в вашем пользовательском классе, если он содержит DataReader, который открыт при возврате на нижний уровень.

Это принятый шаблон при возврате чего-то, что нужно очистить.

3
ответ дан 6 December 2019 в 08:14
поделиться

Во-первых, передача DataReader может быть не совсем тем, что вы хотите сделать, но я предполагаю, что это так.

Правильный способ справиться с этим - передать обратно составной тип, который либо инкапсулирует, либо предоставляет DataReader и удерживает соединение, а затем реализовать IDisposable для этого типа. Утилизируя этот тип, утилизируйте как считыватель, так и соединение.

public class YourClass : IDisposable
{
    private IDbConnection connection;
    private IDataReader reader;

    public IDataReader Reader { get { return reader; } }

    public YourClass(IDbConnection connection, IDataReader reader)
    {
        this.connection = connection;
        this.reader = reader;
    }

    public void Dispose()
    {
        reader.Dispose();
        connection.Dispose();
    }
}
3
ответ дан 6 December 2019 в 08:14
поделиться

Ваш класс

class MyClass : IDisposable
{
  protected List<DataReader> _readers = new List<DataReader>();
  public DataReader MyFunc()
  {
      ///... code to do stuff

      _readers.Add(myReader);
      return myReader;
  }
  private void Dispose()
  {
      for (int i = _readers.Count - 1; i >= 0; i--)
      {
          DataReader dr = _reader.Remove(i);
          dr.Dispose();
      }
      _readers = null;

      // Dispose / Close Connection
  }
}

Затем вне вашего класса

public void FunctionThatUsesMyClass()
{
   using(MyClass c = new MyClass())
   {
       DataReader dr = c.MyFunc();
   }
}

Все читатели и экземпляр MyClass очищаются при выходе из блока using .

2
ответ дан 6 December 2019 в 08:14
поделиться

Я бы ничего не вернул. Вместо этого я бы пропустил делегата.

Например:

void FetchMeSomeReader(Action<IDataReader> useReader)
{
    using(var reader = WhateverYouDoToMakeTheReader())
        useReader(reader);
}

Затем в вызывающем классе:

void Whatever()
{
   FetchMeSomeReader(SetFields);
}

void SetFields(IDataReader reader)
{
   MyListItem = new ListItem(datareader["dc"]);
}
2
ответ дан 6 December 2019 в 08:14
поделиться

Общее правило заключается в том, что класс должен реализовать IDisposable, если он непосредственно содержит неуправляемые ресурсы или содержит ссылку на другой объект IDisposable. Если класс создает IDataReader в одном методе, но никогда не содержит эту ссылку, то вашему классу не нужно будет реализовывать IDisposable в соответствии с правилом (если только он не содержит IDisposable помимо IDataReader, созданного в этом методе).

Реальный вопрос, который вам нужно задать себе, заключается в том, действительно ли ваш класс должен удерживать этот IDataReader даже после того, как он доставил его вызывающему абоненту. Лично я думаю, что это плохой дизайн, потому что он размывает линию собственности. Кто на самом деле владеет IDisposable в этом случае? Кто несет ответственность за его срок службы?Возьмем, к примеру, классы IDbCommand. Они создают экземпляры IDataReader и возвращают их вызывающим абонентам, но освобождают себя от права собственности. Это делает API чистым, и ответственность за управление жизненным времени в этом случае однозначна.

Независимо от вопроса о собственности, ваша конкретная ситуация требует внедрения IDisposable; не потому, что класс создает и возвращает экземпляр IDataReader, а потому, что он звучит так, как будто он содержит объект IDbConnection.

1
ответ дан 6 December 2019 в 08:14
поделиться

Держать соединение с базой данных в качестве переменной-члена в вашем классе читателя и заставить ваш класс читателя реализовать IDisposable кажется мне нормальным.

Однако, вы могли бы рассмотреть возможность сделать ваш метод возвращающим IEnumerable и использовать yield return операторы для прохождения через читателя данных. Таким образом, вы сможете возвращать результаты и продолжать очистку внутри метода.

Вот примерный набросок того, что я имею в виду:

public IEnumerable<Person> ReadPeople(string name)
{
    using (var reader = OpenReader(...))
    {
        // loop through the reader and create Person objects
        for ...
        {
            var person = new Person();
            ...
            yield return person;
        }
    }
}
4
ответ дан 6 December 2019 в 08:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: