【问题标题】:Avoiding dispose of underlying stream避免处理底层流
【发布时间】:2010-04-12 09:02:26
【问题描述】:

我正在尝试模拟一些文件操作。在我拥有的“真实”对象中:

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

在我希望喜欢的模拟对象中:

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

其中 _files 是一个字典,用于存储创建的文件以供以后检查。

但是,当消费者关闭 StreamWriter 时,它释放 MeamoryStream... :-(

对如何追求这个有什么想法吗?

【问题讨论】:

    标签: .net file mocking


    【解决方案1】:

    如果您将 MemoryStream 子类化,这将起作用,但您必须调用 ManualDispose 方法来关闭底层流。
    我不确定,但我认为这个对象超出范围时会被垃圾回收。

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

    编辑:
    如果您希望 MemoryStream 被刷新并准备好从顶部读取,这是一种替代方法。

    public sealed class ManualMemoryStream : MemoryStream
    {
        protected override void Dispose(bool disposing)
        {
            Flush();
            Seek(0, SeekOrigin.Begin);
        }
        public void ManualDispose()
        {
            base.Dispose(true);
        }
    }
    

    【讨论】:

    • 我喜欢这个!但是 Flush() 是不必要的 - 它是需要刷新的“上方”流,此时已经完成了。
    • @danbystrom,很高兴为您提供帮助。你是对的,StreamWriter 会在它被释放之前刷新。但 Seek 很有用。
    【解决方案2】:

    StreamWriter 的本质是在释放底层流时释放它。但是,通过创建(并返回)StreamWriter 的子类(我将称之为 LeakyStreamWriter),您应该能够防止这种默认行为。

    public class LeakyStreamWriter : StreamWriter
    {
        public override void Close()
        {
            BaseStream.Close(); //close, but do not dispose
        }
    
        protected override void Dispose(bool disposing)
        {
            //do nothing here
        }
    }
    

    请注意,我假设 StreamWriter 除了底层流之外没有其他组件要处理,您可能需要检查 StreamWriter 的反汇编以检查这两种方法中实际执行的操作。

    不管怎样,使用上述子类的结果是,当streamwriter关闭时,底层流将被关闭,但不会被释放。

    【讨论】:

    • 够近了!没有调用 Close 并且在 Dispose 中我必须添加一个 Flush()。然后它似乎轻而易举地工作
    • 只需从 Dispose 覆盖调用 base.Dispose(false)。它将正确处理任何 StreamWriter 内部资源,同时保持底层流完好无损(根据定义,因为它是托管资源)。
    猜你喜欢
    • 2010-12-24
    • 2018-01-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2013-08-03
    • 2013-11-16
    • 2015-05-20
    相关资源
    最近更新 更多