6

I'm attempting to mock some file operations. In the "real" object I have:

StreamWriter createFile( string name )
{
  return new StreamWriter( Path.Combine( _outFolder, name ), false, Encoding.UTF8 ) );
}

In the mock object I'd like to have:

StreamWriter createFile( string name )
{
  var ms = new MemoryStream();
  _files.Add( Path.Combine( _outFolder, name ), ms );
  return new StreamWriter( ms, Encoding.UTF8 ) );
}

where _files is a dictionary to store created files for later inspection.

However, when the consumer closes the StreamWriter, it also disposes the MeamoryStream... :-(

Any thoughts on how to pursue this?

Dan Byström
  • 9,067
  • 5
  • 38
  • 68

2 Answers2

9

If you subclass the MemoryStream, this will work but you have to call ManualDispose method to close the underlying stream.
I´m not sure but I think this object will be garbage-collected when it goes out of scope.

public sealed class ManualMemoryStream : MemoryStream
{
    protected override void Dispose(bool disposing)
    {
    }
    public void ManualDispose()
    {
        base.Dispose(true);
    }
}

Edit:
This is an alternative if you want the MemoryStream to be flushed and ready to be read from top.

public sealed class ManualMemoryStream : MemoryStream
{
    protected override void Dispose(bool disposing)
    {
        Flush();
        Seek(0, SeekOrigin.Begin);
    }
    public void ManualDispose()
    {
        base.Dispose(true);
    }
}
Jens Granlund
  • 4,950
  • 1
  • 31
  • 31
  • I like this! But the Flush() is unnecessary - it's the "above" stream that needs flushing, which will already have been done at this point. – Dan Byström Apr 12 '10 at 10:58
  • @danbystrom, glad to help. You are right, the StreamWriter will flush before it´s disposed. But the Seek can be useful. – Jens Granlund Apr 12 '10 at 11:10
3

The nature of the StreamWriter is to dispose the underlying stream when it is itself disposed. However, by creating (and returning) a sub-class of StreamWriter (I'm going to call it LeakyStreamWriter), you should be able to prevent this default behaviour.

public class LeakyStreamWriter : StreamWriter
{
    public override void Close()
    {
        BaseStream.Close(); //close, but do not dispose
    }

    protected override void Dispose(bool disposing)
    {
        //do nothing here
    }
}

Note that I am making the assumption that the StreamWriter has no other components to dispose other than the underlying stream, you may want to check the dissassembly of the StreamWriter to check what is actually done in those two methods.

Anyway, the result of using the above subclass is that the underlying stream will be closed, but not disposed, when the streamwriter is closed.

Alistair Evans
  • 36,057
  • 7
  • 42
  • 54
  • Close enough! Close is not called and in Dispose I must add a Flush(). Then it seems to work like a breeze – Dan Byström Apr 12 '10 at 10:41
  • Just call base.Dispose(false) from the Dispose override. It will properly dispose any StreamWriter internal resources while leaving the underlying stream intact (by definition, as it's a managed resource). – Viktor Svub Sep 27 '12 at 11:02