在处理类实例时,是否需要显式处理其所有IDisposable成员?

时间:2015-08-03 09:05:54

标签: c# .net garbage-collection idisposable

我有一个类,其属性类型为SqlConnectionSqlConnection实施IDisposable。我有以下问题:

  1. 我的班级是否也应该实施IDisposable,因为它具有IDisposable类型的属性?
  2. 如果是,我在处理类的实例时是否需要显式处理属性? E.g。

    public class Helper : IDisposable
    {
        // Assume that it's ANY OTHER IDisposable type. SqlConnection is just an example.
        public SqlConnection SqlConnection { get; set; }
    
        public void Dispose()
        {
            if (SqlConnection!= null)
            {
                SqlConnection.Dispose();
            }
        }
    }
    
  3. 注意: 我知道在实施IDisposable时需要遵循一种模式,但我的问题对于上述情况非常具体。

3 个答案:

答案 0 :(得分:6)

  1. 甚至存在代码分析规则:CA1001: Types that own disposable fields should be disposable

      

    一个类实现了IDisposable接口来处理非托管   它拥有的资源。一个IDisposable类型的实例字段   表示该字段拥有非托管资源。一类   声明IDisposable字段间接拥有非托管资源   并且应该实现IDisposable接口。

    编辑:上述答案始终对父类拥有IDisposable成员有效。

    也就是说,会员的所有权对于像您这样的公共媒体有点模糊:如果SqlConnection实例是在您的课程之外创建的,那么您的课程很可能不是实际拥有该实例,但除了你之外没人知道。

    有一个有趣的例子,关于IDisposable成员是否拥有是否由其父类StreamWriter。关于它有很多问题,例如见这个帖子:Is there any way to close a StreamWriter without closing its BaseStream?

    现在甚至还有一个leaveOpen参数,因此StreamWriter不会处置其基本流。

答案 1 :(得分:4)

取决于。如果您的班级创建拥有,则IDisposable 必须处置(因此,两个答案都是&#34;是&#34; )。 如果您的班级只是使用 IDisposable,那么就不得弃置(所以第一个答案通常是&#34; no&#34; < / strong>,第二个答案是&#34; no&#34; )。

在您的情况下,似乎Helper

  public class Helper
  {
      // Note, that you can assign any arbitrary Connection via this property
      public SqlConnection SqlConnection { get; set; }
      ....
  }

使用 SqlConnection(因为它提供&#34; set&#34;)就像

一样
// It's not helper that owns SqlConnection
using (SqlConnection con = new SqlConnection(...)) {
  ...
  // helper just uses Connection, so helper must not dispose it
  Helper helper = new Helper() {
    SqlConnection = con; 
  };

  ...
}

所以它不得处置连接。相反,像这样的一个班级

public class Helper: IDisposable {
  private SqlConnection m_SqlConnection;

  // Note the absence of public "set"
  public SqlConnection SqlConnection {
    get {
      return m_SqlConnection; 
    } 
  }
  ...
}  

拥有SqlConnection,因此它负责处理它:

using (Helper helper = new Helper(...)) {
  ...
  // it's helper that owns SqlConnection
  SqlConnection con = helper.SqlConnection;
  ...
} 

答案 2 :(得分:1)

两者都是 - 如果您的类负责成员字段的生命周期,那么它需要在该对象上调用Dispose,这意味着您的类需要实现IDisposable以便成员可以在正确的时间处理。

但请注意,您可能不希望为此类成员使用公共可设置属性,因为任何人都可以清除,处置,取消设置,直接重置该字段。您的类需要保持对该字段的控制,这意味着它只能从类本身内部设置 - 最好使用private readonly字段或只读属性。