【发布时间】:2014-02-02 00:09:43
【问题描述】:
在下面的 Dispose 函数中,如果我们是从终结器调用的,我们不会释放我们的流实例。 (是的,我知道这是一个有点复杂的 Dispose 版本,它应该受到虚拟保护,但这是它在我引用的源代码中的编写方式,请参阅下面的 Essential C# 5.0 链接)
class Foo
{
FileInfo File;
Stream Stream;
// yada yada yada more code goes here...
public void Dispose(bool disposing)
{
if (disposing)
{
if (Stream != null)
{
Stream.Dispose();
}
}
if (File != null)
{
File.Delete();
}
}
}
据我了解,这是由于对象的 GC 释放顺序不可预测,包括实例成员。
但是,上面的代码肯定会引发异常(我测试过),如果:
- 客户端开发者忘记直接调用 Dispose()
- 调用的终结器 Dispose(false)
- 尚未处理流
所以 File.Delete() 将失败并抛出 System.IO.IOException 异常。
所以我的问题是, 确保关闭流和删除文件的正确方法是什么? (即使开发人员忘记手动处置对象) 显然访问 Stream 成员(同时 disposing==false)是不安全的,所以必须有办法。
请注意,FileOptions.DeleteOnClose 不是一个选项。动机如下:我有一个类似于 Open's 和 Close's some file 的类,并且跨方法边界使用该文件(即读取数据),并且我不希望在实际使用结束之前删除该文件。
谢谢, 关门
【问题讨论】:
-
你可以随时实现Finalizer,它会被GC调用,以防Dev调用Dispose
-
请注意,在 if (disposing) 之外,您不应该访问 FileInfo 等其他托管对象,因为不能保证它们尚未被释放。
-
好的,这里有个思路,自己创建一个流类,把所有的函数调用转发到一个内部流,当你的流类完成后删除文件。
-
@Bodgan,这就是它在书中的实现方式:books.google.co.il/… 我猜你是对的
-
@Bodgan,可能是因为 FileInfo 不是可终结的类型,即使在终结期间也可以隐式访问它? MS 将 finalizable 定义为覆盖 Finalize 的类型,FileInfo 不符合此条件)。