Reputation: 229058
The StreamWriter.Close() says it also closes the underlying stream of the StreamWriter. What about StreamWriter.Dispose ? Does Dispose also dispose and/or close the underlying stream
Upvotes: 66
Views: 34795
Reputation: 41298
StreamWriter.Close()
just calls StreamWriter.Dispose()
under the bonnet, so they do exactly the same thing.
StreamWriter.Dispose()
does close the underlying stream.
Reflector is your friend for questions like this :)
Upvotes: 66
Reputation: 3458
The Dispose method of StreamWriter also closes the underlying stream. You can check this in the reference source here. One thing that you can do is to use a different constructor, which explicitly tells whether to close or keep the stream open. Check the leaveOpen arg:
public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen) : base(null)
If you plan to leave it open, then it's a good idea to pass the flag set to 'true', but then dispose the stream writer itself, so it doesn't keep a reference to the stream and potentially could dispose other resources (though it doesn't look like there are any resources besides the stream).
Upvotes: 1
Reputation: 5234
The answer is simple, and provided above: yes, disposing a stream closes any underlying stream. Here is an example:
public static string PrettyPrintXML_bug(XDocument document)
{
string Result = "";
using (MemoryStream mStream = new MemoryStream())
{
using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
{
writer.Formatting = Formatting.Indented; // <<--- this does the trick
// Write the XML into a formatting XmlTextWriter
document.WriteTo(writer);
// change the memory stream from write to read
writer.Flush();
mStream.Flush();
} // <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- this also "closes" mStream
mStream.Position = 0;//rewind <-- <-- <-- "cannot Read/Write/Seek"
// Read MemoryStream contents into a StreamReader.
using (StreamReader sReader = new StreamReader(mStream)) // <-- <-- Exception: Cannot access a closed stream
{
// Extract the text from the StreamReader.
Result = sReader.ReadToEnd();
}
}
return Result;
}
and here the solution, where you have to delay Dispose to where the underlying MemoryStream is not needed anymore:
public static string PrettyPrintXML(XDocument document)
{
string Result = "";
using (MemoryStream mStream = new MemoryStream())
{
using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
{
writer.Formatting = Formatting.Indented; // <<--- this does the trick
// Write the XML into a formatting XmlTextWriter
document.WriteTo(writer);
// change the memory stream from write to read
writer.Flush();
writer.Close();
mStream.Flush();
mStream.Position = 0;//rewind
// Read MemoryStream contents into a StreamReader.
using (StreamReader sReader = new StreamReader(mStream))
{
// Extract the text from the StreamReader.
Result = sReader.ReadToEnd();
}
}// <-- here the writer may be Disposed
}
return Result;
}
Looking at these examples, I do not understand why closing the underlying stream is a feature.
I just liked to share this.
Upvotes: 2
Reputation: 1546
Some people will say, just dont dispose the stream, this is a really bad idea, because once the streamwriter goes out of scope GarbageCollection can pick it up anytime and dipose it, thus closing the Handle to the stream, but creating a descendant class which overrides this behaviour of StreamWriter is easy, heres the code:
/// <summary>
/// Encapsulates a stream writer which does not close the underlying stream.
/// </summary>
public class NoCloseStreamWriter : StreamWriter
{
/// <summary>
/// Creates a new stream writer object.
/// </summary>
/// <param name="stream">The underlying stream to write to.</param>
/// <param name="encoding">The encoding for the stream.</param>
public NoCloseStreamWriter(Stream stream, Encoding encoding)
: base(stream, encoding)
{
}
/// <summary>
/// Creates a new stream writer object using default encoding.
/// </summary>
/// <param name="stream">The underlying stream to write to.</param>
/// <param name="encoding">The encoding for the stream.</param>
public NoCloseStreamWriter(Stream stream)
: base(stream)
{
}
/// <summary>
/// Disposes of the stream writer.
/// </summary>
/// <param name="disposing">True to dispose managed objects.</param>
protected override void Dispose(bool disposeManaged)
{
// Dispose the stream writer but pass false to the dispose
// method to stop it from closing the underlying stream
base.Dispose(false);
}
}
If you look in Reflector / ILSpy you will find that the closing of the base stream is actually done in Dispose(true), and when close is called it just calls Dispose which calls Dispose(True), from the code there should be no other side effects, so the class above works nicely.
You might want to add all the constructors though, i have just added 2 here for simplicity.
Upvotes: 19
Reputation: 106796
To quote from Framework Design Guidelines by Cwalina and Abrams in the section about the dispose pattern:
CONSIDER providing method
Close()
, in addition to theDispose()
, if close is standard terminology in the area.
Apparently Microsoft follow their own guidelines, and assuming this is almost always a safe bet for the .NET base class library.
Upvotes: 2
Reputation: 36438
From StreamWriter.Close()
public override void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
From TextWriter.Dispose() (which StreamWriter inherits)
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
They are thus, identical.
Upvotes: 14