65

If I have the following situation:

StreamWriter MySW = null;
try
{
   Stream MyStream = new FileStream("asdf.txt");
   MySW = new StreamWriter(MyStream);
   MySW.Write("blah");
}
finally
{
   if (MySW != null)
   {
      MySW.Flush();
      MySW.Close();
      MySW.Dispose();
   }
}

Can I just call MySW.Dispose() and skip the Close even though it is provided? Are there any Stream implimentations that don't work as expected (Like CryptoStream)?

If not, then is the following just bad code:

using (StreamWriter MySW = new StreamWriter(MyStream))
{
   MySW.Write("Blah");
}
Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
JasonRShaver
  • 4,344
  • 3
  • 32
  • 39
  • 55
    why are you capitalizing your local variables? It hurts my poor head :( – mpen Jul 21 '10 at 21:45
  • 1
    The convention where I am from is to use capitalized local scoped, and lower for params ( NewOrderLineItem vs newOrderLineItem). Just what I am used to =) – JasonRShaver Jul 21 '10 at 22:45
  • possible duplicate of [Close and Dispose - which to call?](http://stackoverflow.com/questions/61092/close-and-dispose-which-to-call) – Binary Worrier Nov 27 '13 at 13:55
  • @BinaryWorrier, the other question is more generic, and covers many different cases. `SqlConnection` exhibits some differences between `Close` and `Dispose`, which `Stream` does not have. – Frédéric Sep 25 '15 at 08:22

8 Answers8

83

Can I just call MySW.Dispose() and skip the Close even though it is provided?

Yes, that’s what it’s for.

Are there any Stream implementations that don't work as expected (Like CryptoStream)?

It is safe to assume that if an object implements IDisposable, it will dispose of itself properly.

If it doesn’t, then that would be a bug.

If not, then is the following just bad code:

No, that code is the recommended way of dealing with objects that implement IDisposable.

More excellent information is in the accepted answer to Close and Dispose - which to call?

Community
  • 1
  • 1
Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
59

I used Reflector and found that System.IO.Stream.Dispose looks like this:

public void Dispose()
{
    this.Close();
}
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
22

As Daniel Bruckner mentioned, Dispose() and Close() are effectively the same thing.

However Stream does NOT call Flush() when it is disposed/closed. FileStream (and I assume any other Stream with a caching mechanism) does call Flush() when disposed.

If you are extending Stream, or MemoryStream etc. you will need to implement a call to Flush() when disposed/closed if it is necessary.

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
ScottS
  • 8,455
  • 3
  • 30
  • 50
  • 2
    I was looking into this recently, and if you're extending MemoryStream, you probably don't need to worry about flushing. Looking at the implementation of Flush for MemoryStream indicates that it's actually a no-op, in fact the documentation states "Overrides Flush so that no action is performed.". – Mike Goatly Jun 23 '11 at 09:19
  • @Mike, if a stream is writing directly to memory with no buffering then flush is unnecessary, if a stream introduces some buffering on top of an otherwise un-buffered stream type a call to flush will be needed. – ScottS Jun 23 '11 at 17:45
  • Can't argue with that - sorry for digging up a 2 year old post! :) – Mike Goatly Jun 23 '11 at 21:08
4

All standard Streams (FileStream, CryptoStream) will attempt to flush when closed/disposed. I think you can rely on this for any Microsoft stream implementations.

As a result, Close/Dispose can throw an exception if the flush fails.

In fact IIRC there was a bug in the .NET 1.0 implementation of FileStream in that it would fail to release the file handle if the flush throws an exception. This was fixed in .NET 1.1 by adding a try/finally block to the Dispose(boolean) method.

Joe
  • 122,218
  • 32
  • 205
  • 338
3

For objects that need to be manually closed, every effort should be made to create the object in a using block.

//Cannot access 'stream'
using (FileStream stream = File.Open ("c:\\test.bin"))
{
   //Do work on 'stream'
} // 'stream' is closed and disposed of even if there is an exception escaping this block
// Cannot access 'stream' 

In this way one can never incorrectly access 'stream' out of the context of the using clause and the file is always closed.

clemahieu
  • 1,419
  • 9
  • 9
3

Both StreamWriter.Dispose() and Stream.Dispose() release all resources held by the objects. Both of them close the underlying stream.

The source code of Stream.Dispose() (note that this is implementation details so don't rely on it):

public void Dispose()
{
    this.Close();
}

StreamWriter.Dispose() (same as with Stream.Dispose()):

protected override void Dispose(bool disposing)
{
    try
    {
        // Not relevant things
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {
            try
            {
                if (disposing)
                {
                    this.stream.Close();
                }
            }
            finally
            {
                // Not relevant things
            }
        }
    }
}

Still, I usually implicitly close streams/streamwriters before disposing them - I think it looks cleaner.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
3

I looked in the .net source for the Stream class, it had the following which would suggest that yes you can...

    // Stream used to require that all cleanup logic went into Close(),
    // which was thought up before we invented IDisposable.  However, we 
    // need to follow the IDisposable pattern so that users can write
    // sensible subclasses without needing to inspect all their base
    // classes, and without worrying about version brittleness, from a
    // base class switching to the Dispose pattern.  We're moving 
    // Stream to the Dispose(bool) pattern - that's where all subclasses
    // should put their cleanup starting in V2. 
    public virtual void Close() 
    {
        Dispose(true); 
        GC.SuppressFinalize(this);
    }

    public void Dispose() 
    {
        Close(); 
    } 
Steve Sheldon
  • 6,421
  • 3
  • 31
  • 35
2

Stream.Close is implemented by a call to Stream.Dispose or vice versa - so the methods are equivalent. Stream.Close exists just because closing a stream sounds more natural than disposing a stream.

Besides you should try to avoid explicit calls to this methods and use the using statement instead in order to get correct exception handling for free.

Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143