【问题标题】:Why calling Dispose() on BinaryReader results in compile error?为什么在 BinaryReader 上调用 Dispose() 会导致编译错误?
【发布时间】:2010-09-18 09:21:27
【问题描述】:

我有以下类在内部使用 BinaryReader 并实现 IDisposable。

类 DisposableClass : IDisposable { 私人 BinaryReader 阅读器; 公共 DisposableClass(流流) { reader = new BinaryReader(stream); } protected virtual void Dispose(bool disposing) { 如果(处置) { ((IDisposable)reader).Dispose(); // reader.Dispose();// 这不会编译 } } 公共无效处置() { this.Dispose(true); } }

我已经知道我需要将 BinaryReader 转换为 IDisposable 才能对其调用 Dispose,但我不明白为什么我不能直接调用 Dispose() 方法而不转换为 IDisposable?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    因为BinaryReader 上的Dispose 方法已经显式实现,所以它不起作用。

    而不是隐式实现,如:

    public void Dispose()
    {
    }
    

    ...已经明确实现,如:

    void IDisposable.Dispose()
    {
    }
    

    ...这意味着它只能通过IDisposable 接口访问。因此,您必须先将实例转换为IDisposable

    【讨论】:

    • 完美的例子说明为什么你不应该偏离标准的 Dispose 模式。
    • 或者只是调用 BinaryReader.Close() 来做同样的事情。
    • 即便如此,如果你实现了一个 Close() 方法,它应该完成通常在 Dispose() 中完成的工作,而 Dispose() 应该简单地调用 Close()。无论如何,BinaryReader 没有正确遵循模式。
    • @Scott - 确实如此。奇怪的是,MSDN 文档声明 Dispose 只能在内部使用——这让我相信 Close 做了额外的工作。但是,Reflector 表明 Close 和 Dispose 是等价的。似乎将来可以清除它而无需担心向后兼容....
    • @Mark,您是对的,文档确实声明“此 API 支持 .NET Framework 基础结构,不打算直接从您的代码中使用。”这就是说它没有遵循模式的进一步原因。
    【解决方案2】:

    扩展我的 cmets hereBinaryReader 类没有正确实现 Dispose 模式。

    在 Reflector 中查看这个类,它看起来像这样(对于 .NET 3.5):

    public class BinaryReader : IDisposable
    {
        public virtual void Close()
        {
           this.Dispose(true);
        }
        protected virtual void Dispose(bool disposing)
        {
           if (disposing)
           {
              Stream stream = this.m_stream;
              this.m_stream = null;
              if (stream != null)
              {
                 stream.Close();
              }
           }
           this.m_stream = null;
           this.m_buffer = null;
           this.m_decoder = null;
           this.m_charBytes = null;
           this.m_singleChar = null;
           this.m_charBuffer = null;
       }
       void IDisposable.Dispose()
       {
          this.Dispose(true);
       }
    }
    

    这里的问题是,通过使IDisposable.Dispose() 成为显式接口实现,它会强制开发人员调用Close() 而不是Dispose()

    在这种情况下,我们遇到了语义不平衡的情况。从来没有调用“打开”阅读器,因此“关闭”阅读器并不直观。

    更进一步,为了调用 Dispose(),您必须显式转换为 IDisposable,这不是您通常需要做的事情。你可以选择直接调用Dispose(bool),但是你怎么知道布尔参数应该是什么?

    为了正确地遵循模式,它应该被实现为:

    public class BinaryReader : IDisposable
    {
        public virtual void Close()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
           if (disposing)
           {
              Stream stream = this.m_stream;
              this.m_stream = null;
              if (stream != null)
              {
                 stream.Close();
              }
           }
           this.m_stream = null;
           this.m_buffer = null;
           this.m_decoder = null;
           this.m_charBytes = null;
           this.m_singleChar = null;
           this.m_charBuffer = null;
       }
       public void Dispose()
       {
          this.Close();
       }
    }
    

    这将允许您调用Close()Dispose(),在这种情况下,任一调用都会继续导致调用Dispose(true)。 (通过调用Close()((IDisposable)reader).Dispose(),这与实际实现的流程相同。

    幸运的是(或者不幸的是,这取决于您选择查看它的方式),因为BinaryReader 确实实现了IDisposable 接口,它在 using 语句中是允许的:

    using (BinaryReader reader = new BinaryReader(...))
    {
    }
    

    【讨论】:

    • “你可以选择直接调用 Dispose(bool)”——它是受保护的,所以这不是一个选项。
    • @Mark,您的评论自相矛盾...Dispose(bool) 受到保护,因此除非您从 BinaryReader 继承,否则无法直接访问它,在这种情况下,根据使用情况,这可能是一个选项。跨度>
    【解决方案3】:

    实际上他们选择使用 Close() 而不是 Dispose() Dispose 已明确实施。这就是为什么你看不到它。

    但是 Close 与 dispose 做同样的事情,这是他们希望您使用的方法。 Reflector 为 Close 方法提供了以下反汇编

    public virtual void Close()
    {
        this.Dispose(true);
    }
    

    使用 Close() 是因为它是二进制阅读器上下文中更好的单词选择。

    【讨论】:

    • 知道他们为什么走这条路吗?
    猜你喜欢
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2019-08-30
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 2012-10-05
    相关资源
    最近更新 更多