我应该在这里实现IDisposable吗?

时间:2010-05-19 16:53:59

标签: c# .net idisposable sqldatareader

我调用SQL Server的方法返回DataReader,但是由于我需要做什么 - 将DataReader返回到驻留在页面代码隐藏的调用方法中 - 我可以' t关闭调用SQL Server的方法的类中的连接。因此,我没有最终或使用块。

处理资源的正确方法是使类实现IDisposable吗?或者,我应该从调用者那里明确地处置非托管资源(类级别字段)吗?

编辑:我发回datareader是因为我需要将特定数据从datareader绑定到listitem控件,所以在调用类(Codebehind页面)中,我这样做:

 new ListItem(datareader["dc"]); (along those lines).

7 个答案:

答案 0 :(得分:7)

我会说是的,实施IDisposable。据我所知,使用它的主要原因之一是当你不能相信对象的用户足以自己正确地做到这一点。这似乎是这方面的主要候选人。

然而,有人说,您的架构存在问题。为什么要将DataReader本身发送到页面而不是通过返回必要的方法调用方法为您执行此操作(包括相关的清理)?如果有必要将实际读者提供给页面,那就这样吧。

答案 1 :(得分:4)

将数据库连接作为成员变量保存在读者类中并使读者类实现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;
        }
    }
}

答案 2 :(得分:3)

是的,如果它包含一个在返回到较低层时打开的DataReader,则应在自定义类上实现IDisposable。

返回的东西是可接受的模式,需要清理。

答案 3 :(得分:3)

首先,传递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();
    }
}

答案 4 :(得分:2)

你的班级

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实例都会被清除。

答案 5 :(得分:2)

我不会回报任何东西。相反,我会通过代表。

例如:

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

然后在您的通话类中:

void Whatever()
{
   FetchMeSomeReader(SetFields);
}

void SetFields(IDataReader reader)
{
   MyListItem = new ListItem(datareader["dc"]);
}

答案 6 :(得分:1)

一般规则是,如果类直接保存非托管资源或保存对另一个IDisposable对象的引用,则应该实现IDisposable。如果您的班级在一个方法中创建IDataReader但从未保留该引用,则您的班级不需要按照规则实施IDisposable(除非它恰好在{1}}之外保留IDisposable {1}在这一种方法中创建。)

你需要问自己的真正问题是,即使你的班级已经将它传递给来电者,你的班级是否真的应该坚持IDataReader。就个人而言,我认为这是一个糟糕的设计,因为它模糊了所有权。在这种情况下谁实际拥有IDataReader?谁对其一生负责?以IDisposable类为例。他们创建IDbCommand个实例并将它们返回给调用者,但是他们自己解除了所有权。这使得API干净,在这种情况下,终身管理的责任是明确的。

无论所有权问题如何,您的具体情况都需要实施IDisposable;不是因为你的类碰巧创建并返回一个IDataReader实例,而是因为它听起来像是拥有一个IDataReader对象。