9

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.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Learner
  • 4,661
  • 9
  • 56
  • 102

3 Answers3

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

Community
  • 1
  • 1
ken2k
  • 48,145
  • 10
  • 116
  • 176
  • 2
    Yes, the types that *own* IDisposable should maintain (i.e. *dispose* them). However, the class in the question doesn't seem to *own* `SqlConnection`: see public "set" - so you can assign *arbitrary* `SqlConnection` to a `Helper` instance. `Helper` *uses* SqlConnection and that's why *should not dispose* it. – Dmitry Bychenko Aug 03 '15 at 09:59
  • @DmitryBychenko Your point is valid, members should be disposed if they are owned by the parent class. An interesting example is `StreamWriter` that could own (or not) its inner stream. Let's not oversimply things, I'm editing a bit to clarify. – ken2k Aug 03 '15 at 10:12
  • @DmitryBychenko Edited + upvoted your answer as it's more accurate. I didn't notice the name of the OP's class (Helper), so chances are it indeed doesn't own the SQL connection. – ken2k Aug 03 '15 at 10:22
6

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;
  ...
} 
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Don't want to open a new question that is marked as dup right away, but how does `StreamReader` etc. apply to that? These classes receive an underlying stream via constructor (so from a client), but dispose them in their `Close` or `Dispose` methods. Is this the correct pattern (to dispose what you get via constructor and can't be reset during "your" lifetime)? – René Vogt Apr 26 '16 at 13:53
  • 1
    @René Vogt: `StreamReader` is a correct pattern *Decorator*: we *wrap* `Stream` into `StreamReader` and use `StreamReader` instead of `Stream`, and so `StreamReader` owns the Stream. A bit exaggerated example is reading encrypted archived text from file - StreamReader, ZipStream, CryptoStream are all *decorators* which are owners of prior ones – Dmitry Bychenko Apr 26 '16 at 14:00
1

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.

Fernando Matsumoto
  • 2,697
  • 1
  • 18
  • 24
thecoop
  • 45,220
  • 19
  • 132
  • 189