在处置 class 实例时,我是否需要显式处置其所有 IDisposable 成员?

While disposing the class instance, do i need to dispose all its IDisposable members explicitly?

我有一个 class,它有一个 属性 SqlConnection 类型。 SqlConnection 实施 IDisposable。我有以下问题:

  1. 我的 class 是否也应该实施 IDisposable 只是因为它具有 IDisposable 类型的 属性?

  2. 如果是,我是否需要 Dispose 属性 显式 当我处理我的 class?例如

    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();
            }
        }
    }
    

注意: 我知道在实施 IDisposable 时需要遵循一种模式,但我的问题是针对上述案例的。

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

但是请注意,您可能不想为这样的成员使用 public 可设置 属性,因为这样任何人都可以直接清除、处理、取消设置、重置该字段。您的 class 需要保持对该字段的控制,这意味着它只能从 class 本身内部设置 - 理想情况下使用 private readonly 字段或只读 属性.

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

A class implements the IDisposable interface to dispose of unmanaged resources that it owns. An instance field that is an IDisposable type indicates that the field owns an unmanaged resource. A class that declares an IDisposable field indirectly owns an unmanaged resource and should implement the IDisposable interface.


编辑:以上答案始终对 parent 拥有IDisposable 成员有效class.

也就是说,成员的 所有权 对于像您这样的 public 属性有点模糊:如果 SqlConnection 实例是在您的 class,您的 class 很可能 而不是 实际上拥有该实例,但除了您之外没有人知道。

关于 IDisposable 成员是否由其 parent class 拥有 有一个有趣的例子:StreamWriter.有很多关于它的问题,例如这个线程:Is there any way to close a StreamWriter without closing its BaseStream?

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

取决于。如果您的 class 创建 并且 拥有 IDisposable 必须处置 (所以,两个答案都是"yes")。 如果你的 class 只是 使用 IDisposable 一定不能处理 它(所以第一个答案通常是 "no" 第二个答案是 "no").

在你的情况下,似乎 Helper class

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

只是使用 SqlConnection(因为它提供"set")就像

// 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; 
  };

  ...
}

所以它不能释放连接。相反,一个class那样的

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;
  ...
}