tags:

views:

169

answers:

2

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 imaginery 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;
}
+5  A: 

Unfortunately not - the 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.
Jon Skeet
That'll do nicely. Thanks :)
Binary Worrier
Jon: If you don't mind I'm actually going to give this answer to Darin, correctly using an existing class suits my specific need. Thanks for MiscUtil though, some nice stuff in there :)
Binary Worrier
@Binary Worrier: I have no problems with that at all. Admittedly my answer gave that option as well, but let's spread the joy :)
Jon Skeet
@Jon: Bugger, missed that!
Binary Worrier
+2  A: 

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.

Darin Dimitrov
Of course, there is then an implementation detail: does it buffer any data? Personally I'd rather use `NonClosingStreamWrapper` from MiscUtil
Marc Gravell
@Marc, wouldn't calling `Flush` do the job in case it buffers data?
Darin Dimitrov
@Darin - maybe yes, but actually I know of several `Stream` implementations that don't respect `Flush` (only fully flushing on `Close`; so again you'd have to treat it as an implementation detail, IMO.
Marc Gravell
Fine, but once we exit CreateStream, the StreamWrtier is collectable, forcing the third part reader to race against the GC, which is not a situation I want to be left in. Or am I missing something?
Binary Worrier
@BinaryWorrier: No, there's no race condition: StreamWriter doesn't have a finalizer (and indeed shouldn't).
Jon Skeet
@Jon Skeet: Really? I *am* surprised. I assumed anything that implements Dispose had a finalizer. One shall look in future and be done with assuming. @Darin +1 apologies for casting aspersions upon your answer.
Binary Worrier
@Binary Worrier: You should only have a finalizer if you *directly* own the resource. In this case, the StreamWriter should assume that the Stream will clean itself up if it needs to.
Jon Skeet
@Darin Dimitrov: In that case the answer goes to you, thanks.
Binary Worrier