Is there any way to close a StreamWriter without closing its BaseStream?

C#StreamDispose

C# Problem Overview


My root problem is that when using calls Dispose on a StreamWriter, it also disposes the BaseStream (same problem with Close).

I have a workaround for this, but as you can see, it involves copying the stream. Is there any way to do this without copying the stream?

The purpose of this is to get the contents of a string (originally read from a database) into a stream, so the stream can be read by a third party component.
NB: I cannot change the third party component.

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    baseCopy.Seek(0, System.IO.SeekOrigin.Begin);
    return baseCopy;
}

Used as

public void Noddy()
{
    System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
    My3rdPartyComponent.ReadFromStream(myStream);
}

Ideally I'm looking for an imaginary method called BreakAssociationWithBaseStream, e.g.

public System.IO.Stream CreateStream_Alternate(string value)
{
    var baseStream = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        writer.BreakAssociationWithBaseStream();
    }
    return baseStream;
}

C# Solutions


Solution 1 - C#

If you are using .NET Framework 4.5 or later, there is a StreamWriter overload using which you can ask the base stream to be left open when the writer is closed.

In earlier versions of .NET Framework prior to 4.5, StreamWriter assumes it owns the stream. Options:

  • Don't dispose the StreamWriter; just flush it.

  • Create a stream wrapper which ignores calls to Close/Dispose but proxies everything else along. I have an implementation of that in MiscUtil, if you want to grab it from there.

Solution 2 - C#

.NET 4.5 has a new method for that:

StreamWriter(Stream, Encoding, Int32, Boolean)

public StreamWriter(
    Stream stream,
    Encoding encoding,
    int bufferSize,
    bool leaveOpen
)

Solution 3 - C#

Simply don't call Dispose on the StreamWriter. The reason this class is disposable is not because it holds unmanaged resource but to allow the disposal of the stream which itself could hold unmanaged resources. If the life of the underlying stream is handled elsewhere, no need to dispose the writer.

Solution 4 - C#

Memory stream has a ToArray property that can be used even when stream is closed. To Array writes the stream contents to a byte array, regardless of the Position property. You can create a new stream based on the stream you wrote in.

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    var returnStream = new System.IO.MemoryStream( baseCopy.ToArray());
    return returnStream;
}

Solution 5 - C#

You need to create a descendant of the StreamWriter and override its dispose method, by always passing false to the disposing parameter, it will force the stream writer NOT to close, the StreamWriter just calls dispose in the close method, so there is no need to override it (of course you can add all the constructors if you want, i just have one):

public class NoCloseStreamWriter : StreamWriter
{
    public NoCloseStreamWriter(Stream stream, Encoding encoding)
        : base(stream, encoding)
    {
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(false);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBinary WorrierView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#maligerView Answer on Stackoverflow
Solution 3 - C#Darin DimitrovView Answer on Stackoverflow
Solution 4 - C#TudorView Answer on Stackoverflow
Solution 5 - C#Aaron MurgatroydView Answer on Stackoverflow