Question

I know there are a number of threads on here about how to use the using statement and calling the Dispose() method. I have read the majority of these threads.

If I call Dispose(), does it call Close()?

If I want to use an object (say SqlDataReader), but then use it again in another code block, should I not call Dispose()? Which also means to omit the using statement.

Also, to clarify, if a FileStream is wrapping a StreamWriter and I call dispose on the FileStream, this will call Flush(), Close() and Dispose() (depending on whether Dispose() calls Close()) on the StreamWriter, right? Likewise, if I call Close on the FileStream, this will only call Flush() and Close() on the FileStream.

Is checking IL a good way to answer these questions about what is happening under the hood?

Was it helpful?

Solution

If I call Dispose(), does it call Close()?

Calling Dispose should take any required actions to dispose of the resource, which should be similar, if not identical to, calling Close. This, however, is an implementation detail and not necessarily guaranteed (though we can expect that the BCL follows this guideline).

If I want to use an object (say SqlDataReader), but then use it again in another code block, should I not call Dispose()? Which also means to omit the using statement.

If you want to use the object again, you definitely should not dispose it. However, you should typically use two separate connections if you're going to the database two separate times. It's generally not a good idea to keep an IDataReader around an longer than is needed to grab your needed data.

Also, to clarify, if a FileStream is wrapping a StreamWriter and I call dispose on the FileStream, this will call Flush(), Close() and Dispose() (depending on whether Dispose() calls Close()) on the StreamWriter, right? Likewise, if I call Close on the FileStream, this will only call Flush() and Close() on the FileStream.

Disposing an object that wraps another disposable object should call Dispose on the interior object. Calling Close on a FileStream will call its Dispose method under the good, so it will also act on both streams.

Is checking IL a good way to answer these questions about what is happening under the hood?

Checking IL will definitely answer most of these questions definitively. As @Rich says, you can also just try debugging your own Dispose implementations. There is also, of course, MSDN documentation to start with before you try to figure it out yourself, and Reflector if you don't want to muck around in IL.

OTHER TIPS

"If I call Dispose(), does it call Close()?"

In theory, it should. The BCL classes all do this, but it is up to the library author to correctly handle this. If the library you are using is done correctly, Dispose() should also Close() [and Close() will Dispose() - the calls should be interchangable].

"If I want to use an object (say SqlDataReader), but then use it again in another code block, should I not call Dispose()? Which also means to omit the using statement."

Correct. If you use the using statement, it will always call Dispose(). This will close the data reader before your other block can use it.

"Also, to clarify, if a FileStream is wrapping a StreamWriter and I call dispose on the FileStream, this will call Flush(), Close() and Dispose() (depending on whether Dispose() calls Close()) on the StreamWriter, right? Likewise, if I call Close on the FileStream, this will only call Flush() and Close() on the FileStream."

If you are wrapping a FileStream around a StreamWriter, I highly recommend treating them consistently. Use a single using statement with both members, so they are both disposed of at the end of the block. This is the safest, most clean approach.

"Is checking IL a good way to answer these questions about what is happening under the hood?"

It is a way - although a more difficult way. Read up on MSDN about using and streams, and the documentation will explain it in simpler terms than trying to parse the IL. The IL will tell you EXACTLY what happens, though, if you are curious.

If I call Dispose(), does it call Close()?

Close() and Dispose() do the same if implemented properly; it is just a naming thing. It sounds more plain to close a file than to dispose it. See Implementing Finalize and Dispose to Clean Up Unmanaged Resources esspecialy 'Customizing a Dispose Method Name'.

If I want to use an object (say SqlDataReader), but then use it again in another code# block, should I not call Dispose()? Which also means to omit the using statement.

Yes, because the object gets disposed on exiting the using block.

Also, to clarify, if a FileStream is wrapping a StreamWriter and I call dispose on the > FileStream, this will call Flush(), Close() and Dispose() (depending on whether Dispos() calls Close()) on the StreamWriter, right? Likewise, if I call Close on the FileStream, > this will only call Flush() and Close() on the FileStream.

It is the other way; a StreamWriter is based on an underlying stream an closing the StreamWriter closes the underlying stream that may be a FileStream; see the MSDN for reference. Hence a single using statement for the StreamWriter is sufficent.

If I call Dispose(), does it call Close()?

Not necessarily. I sometimes use Reflector to check what actually happens in Close and Dispose.

If I want to use (...) it again in another code block, should I not call Dispose()?

Correct. Call Dispose when you're done. But that doesn't mean you always want to keep your object alive for a long time - you can sometimes benefit from creating multiple instances (multiple using constructs) -- e.g. You might wan to close a connection as soon as possible, but then create a new one again when you need it.

As you said, there are lot of resources on that, but I will include the MSDN link for some guidelines: Implementing Finalize and Dispose to Clean Up Unmanaged Resources.

Dispose is the main method linked to the IDisposable interface and the Disposable pattern.

Microsoft calls a method like Close() a Domain Specific Alias, and that gives the idea. But it is still up to the Implementor of the Class, there could be differences, like being able to reopen or not. But in general you shouldn't (have to) care.

The sqlDataReader is a bit of a bad example because you can not reuse it. And that's in general the best advice for all other Disposable objects too.

An easier way to debug this than going through the IL code would be to derive from your IDisposable, override the necessary methods doing nothing but calling base.[Method Name](), and set a breakpoint in each one. Then if you wrap your derived class in a using block, you'll see the lifecycle of these calls.

No, IDisposable does not require Close(), but the object implementing IDispose may be nice enough to include it in the Dispose() method.

You should dispose it as soon as you have the piece of data you are getting from the DB. Don't leave a reader open any longer than you need. If you are doing any real work with the data, use a dataAdapter/dataset instead of reader.

No Idea. Check the Generated IL

I try to move the using clause higher up, since I prefer to use that syntax. Then call the other blocks using that resource from inside that using block.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top