为啥在 BinaryReader 上调用 Dispose() 会导致编译错误?
Posted
技术标签:
【中文标题】为啥在 BinaryReader 上调用 Dispose() 会导致编译错误?【英文标题】: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?
【问题讨论】:
【参考方案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 here,BinaryReader
类没有正确实现 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() 是因为它是二进制阅读器上下文中更好的单词选择。
【讨论】:
知道他们为什么走这条路吗?以上是关于为啥在 BinaryReader 上调用 Dispose() 会导致编译错误?的主要内容,如果未能解决你的问题,请参考以下文章
如果我正在读取的字节还不存在,BinaryReader 会做啥?
BinaryReader.PeekChar()读取了多少位?