While disposing the class instance, do i need to d

2020-04-02 17:58发布

I have a class which has a property of the type SqlConnection. SqlConnection implements IDisposable. I have following questions:

  1. Should my class also implement IDisposable just because it has property of type IDisposable?
  2. If yes, do i need to Dispose the property explicitly when I am disposing instance of my class? 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();
            }
        }
    }
    

Note : I know that there is a pattern to be followed while implementing IDisposable but my question is very specific to the case mentioned above.

3条回答
甜甜的少女心
2楼-- · 2020-04-02 18:33

It depends. If your class creates and owns the IDisposable it must dispose it (so, both answers are "yes"). If your class just uses IDisposable it must not dispose it (so the first answer is, usually, "no" and the second answer is "no").

In your case, it seems that Helper class

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

just uses SqlConnection (because it provides "set") in the way like

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

  ...
}

so it must not dispose the connection. On the contrary, a class like that

public class Helper: IDisposable {
  private SqlConnection m_SqlConnection;

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

owns its SqlConnection so it's responsible for disposing it:

using (Helper helper = new Helper(...)) {
  ...
  // it's helper that owns SqlConnection
  SqlConnection con = helper.SqlConnection;
  ...
} 
查看更多
够拽才男人
3楼-- · 2020-04-02 18:35

Yes for both - if your class is responsible for the lifecycle of a member field, then it needs to call Dispose on that object, which means your class needs to implements IDisposable so that the member can be disposed at the correct time.

However, note that you likely don't want to use a public settable property for such a member, as then anyone can clear, dispose, unset, reset that field directly. Your class needs to maintain control of that field, which means it should only be settable from inside the class itself - ideally using a private readonly field or readonly property.

查看更多
孤傲高冷的网名
4楼-- · 2020-04-02 18:36
  1. Yes

  2. Yes

There even exists a Code Analysis rule for that: 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.


EDIT: the above answer is always valid for IDisposable members that are owned by the parent class.

That said, the ownership of a member is kinda vague for public properties like yours: if the SqlConnection instance is created outside your class, chances are your class is not actually owning the instance, but nobody knows that except you.

There is a funny example about whether an IDisposable member is owned or not by its parent class: StreamWriter. There are lots of question about it, see for example this thread: Is there any way to close a StreamWriter without closing its BaseStream?

Now there even is a leaveOpen parameter so the StreamWriter doesn't dispose its base stream.

查看更多
登录 后发表回答