C# compiler option to find classes that implement IDisposable

C

Carl Johansson

Being quite new to C#, I may have misunderstood this. If so please bear with
me!

As far as I can understand, any instances of a class that implements the
IDisposable interface must call the Dispose method not create leaks of
resources!? This can be accomplished by explicitly calling Dispose or
through the "using" statement.

For example, a recursive method that creates hundreds or thousands of
instances of, for example, OleDbConnection, OleDbCommand, and
OleDbDataReader, would eventually cause havoc unless they were explicitly
disposed through the Dispose method or the using statement, right?

Now, if all of the above is true, what is the easiest way to identify all
classes the implement the IDisposable interface? The "Auto list members"
pop-up window i VS will show the Dispose method if it is present, but then I
must always be alert, and that, I am not! Is it possible to get the C#
compiler to generate warning messages about these classes when used?

Best Regards Carl Johansson
 
J

Jon Skeet [C# MVP]

Being quite new to C#, I may have misunderstood this. If so please bear with
me!

As far as I can understand, any instances of a class that implements the
IDisposable interface must call the Dispose method not create leaks of
resources!? This can be accomplished by explicitly calling Dispose or
through the "using" statement.

No, the instances don't call Dispose - the *clients* of those classes
call Dispose.
That doesn't mean it's always cut-and-dried as to where things should
be disposed. For instance, if you create a Stream and pass it into
Image.FromStream, you need to leave the stream open - image will close
it when the image is disposed.
For example, a recursive method that creates hundreds or thousands of
instances of, for example, OleDbConnection, OleDbCommand, and
OleDbDataReader, would eventually cause havoc unless they were explicitly
disposed through the Dispose method or the using statement, right?
Yes.

Now, if all of the above is true, what is the easiest way to identify all
classes the implement the IDisposable interface? The "Auto list members"
pop-up window i VS will show the Dispose method if it is present, but then I
must always be alert, and that, I am not! Is it possible to get the C#
compiler to generate warning messages about these classes when used?

No - because you don't always want to dispose of something in the same
place you create it.

I'm afraid you basically have to be disciplined about it.

Jon
 
J

james

Carl,

The objects dispose themselves when they are memory collected.
Nothing tricky... its part of the design pattern. For
OleDbConnection, an ancestor has

~Component()
{
this.Dispose(false);
}

and Dispose is virtual.

You should call Dispose on IDisposables when you are finished because
it might be a while before the memory collector runs, but forgetting
will not cause "havoc".

-James
 
J

Jon Skeet [C# MVP]

The objects dispose themselves when they are memory collected.

You should almost *never* rely on this, however. If something
implements IDisposable, you should call Dispose when you're done with
it.

The finalizer is merely a "belt and braces" approach in case you
forget to explicitly dispose things.

You should call Dispose on IDisposables when you are finished because
it might be a while before the memory collector runs, but forgetting
will not cause "havoc".

Um, it could do. If you forget to close connections explicitly, you
could end up running out of connections unnecessarily. Likewise not
disposing of a FileStream could stop you from then reopening the file
for writing.
This is also non-deterministic - so reproducing this issue reliably
could almost impossible.

Personally, I count that as "havoc"...

Jon
 
B

Brian Gideon

Carl,

The objects dispose themselves when they are memory collected.
Nothing tricky... its part of the design pattern. For
OleDbConnection, an ancestor has

~Component()
{
this.Dispose(false);

}

and Dispose is virtual.

You should call Dispose on IDisposables when you are finished because
it might be a while before the memory collector runs, but forgetting
will not cause "havoc".

-James

Omitting a call to Dispose could be problematic in scenarios where the
object holds onto a resource in a manner that prevents other objects
from acquiring the same resource. Even though you may be finished
using that resource logically it might not be released until the GC
runs. If you create another instance that attempts to access the same
resource an exception may be thrown.
 
J

james

Jon,

I was trying to say that for someone just learning C# they don't need
to obsess over finding every IDisposable.

If you use the wizards in Visual Studio you can write an database
application without writing much code, and the worst thing would be to
kludge in calling Dispose everywhere because you aren't sure if the
generated code does that.

-James
 
J

Jon Skeet [C# MVP]

I was trying to say that for someone just learning C# they don't need
to obsess over finding every IDisposable.

Well, I think it's a good idea to be aware of it right from the start,
and try to build up an understanding of what implements IDisposable,
calling it appropriately. Best not to get into bad habits, IMO. I've
seen far too much code which calls Stream.Close() explicitly without
using a finally block etc - if you get into the habit of using a
"using" statement where appropriate, you don't end up with code like
that.
If you use the wizards in Visual Studio you can write an database
application without writing much code, and the worst thing would be to
kludge in calling Dispose everywhere because you aren't sure if the
generated code does that.

Well, that would certainly be bad - but so would saying, "Oh, it's
okay - the finalizer will take care of it."
The latter will lead to hard-to-reproduce bugs.

Jon
 
D

Doug Semler

james said:
Jon,

I was trying to say that for someone just learning C# they don't need
to obsess over finding every IDisposable.

I disagree. That's like saying that someone just learning C++ doesn't need
to worry about what the "virtual" keyword on a destructor declaration means.


--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 
B

Brian Gideon

I disagree. That's like saying that someone just learning C++ doesn't need
to worry about what the "virtual" keyword on a destructor declaration means.

--

I don't know...I mean since James used the word obsess I can't
disagree too much. Afterall, if you obsessed over *every* little
detail during the learning process you'd almost certainly develop some
negative level of frustration.
 
D

Doug Semler

Brian Gideon said:
I don't know...I mean since James used the word obsess I can't
disagree too much. Afterall, if you obsessed over *every* little
detail during the learning process you'd almost certainly develop some
negative level of frustration.


For me, unfortunately (or fortunately??) the words "worry" and "obsess" mean
almost the exact same thing. Psychological thing I guess...

On the other hand, not understanding the various features and semantics of
the language/environment in which you are programming, whether it be the
nuances of IDisposable or virtual destructors or even whether the modulus
operator result is negative depending upon the sign of the dividend or
divisor can be "dangerous".

--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 
B

Brian Gideon

For me, unfortunately (or fortunately??) the words "worry" and "obsess" mean
almost the exact same thing. Psychological thing I guess...

On the other hand, not understanding the various features and semantics of
the language/environment in which you are programming, whether it be the
nuances of IDisposable or virtual destructors or even whether the modulus
operator result is negative depending upon the sign of the dividend or
divisor can be "dangerous".

It certainly can be dangerous. That's why I make it a point to obsess
over details during the development of a production quality system.
But, for me anyway, when I learn a new language or technology I like
to just get the general idea of a concept and move on. I'll come back
later to fill in the gaps. That way I can move forward without
getting too hung up on a confusing or complex concept.

Threading is a good example of this. The details can get incredibly
confusing in a hurry. It's nice to get the general gist of all the
higher level concepts before you really dive down and understand the
specifics. My hunch is that's how most people like to learn...or may
it's just me :)
 
J

Jon Skeet [C# MVP]

Brian Gideon said:
It certainly can be dangerous. That's why I make it a point to obsess
over details during the development of a production quality system.
But, for me anyway, when I learn a new language or technology I like
to just get the general idea of a concept and move on. I'll come back
later to fill in the gaps. That way I can move forward without
getting too hung up on a confusing or complex concept.

Threading is a good example of this. The details can get incredibly
confusing in a hurry. It's nice to get the general gist of all the
higher level concepts before you really dive down and understand the
specifics. My hunch is that's how most people like to learn...or may
it's just me :)

I work the other way round - rather than start off with a great big app
without really knowing how it works, I like to start off with an almost
trivial task but make sure I know as much as possible about how
everything works before I move up to the next stage.

Basically, I like building on really firm foundations. It's definitely
a personal preference though. It's often nice to get a *glimpse* of the
big picture before moving onto the detail, of course - but I really
don't feel comfortable doing too much without decent understanding.
 
C

Carl Johansson

Here is a practical question. Suppose I have the following code:

public partial class MyForm : Form
{
Font boldFont; //Used throughout MyForm

public MyForm()
{
InitializeComponent();
boldFont = new Font(myControl.Font, FontStyle.Bold);
}

//Other code using boldFont...
}

Now, at some point boldFont is somehow automatically disposed of by the GC
(which I know very little about)?

I.e. I don't have to worry about whether boldFont is going to be disposed of
or not?

Or, should I implement a "better safe than sorry strategy" and let a
destructor explicitly dispose boldFont?

I do find this topic a bit confusing. It feels like .NET is telling me:
"With me you no longer have to worry about returning resources. I'll take
care of it for you ('Wow' feeling here!), unless I don't know how to... ('I
knew it was too good to be true' feeling here)".

Are there some web documents (or part of a book) that can explain this topic
in an easy to follow way?

Best Regards Carl Johansson
 
S

Samuel R. Neff

If you instantiate it and it's IDisposable, then it's your
responsibility to call Dispose. In your case you're extending Form
which has a protected Dispose implementation already which you should
piggyback on top of.

protcted override void Dispose(bool disposing) {
super.Dispose(disposing);
if (disposing) {
if (boldFont != null) {
boldFont.Dispose();
}
}
}

IDisposable is basically an acknowledgement that the component
developer still needs control over how certain resources are released
and it means application developers can not ignore resource management
entirely.

Sam
 
J

james

I disagree. That's like saying that someone just learning C++ doesn't need
to worry about what the "virtual" keyword on a destructor declaration means.

I never said you shouldn't understand IDisposable or that you
shouldn't use it. Jon only explained half of the pattern... the fact
that Dispose is called by the Finalizer is important.

-James
 
D

Doug Semler

james said:
I never said you shouldn't understand IDisposable or that you
shouldn't use it. Jon only explained half of the pattern... the fact
that Dispose is called by the Finalizer is important.


The fact that Dispose may NOT be called by the Finalizer (if it doesn't
implement the pattern properly) or is called by the Finalizer in a non
deterministic manner is more important. :)

--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top