删除流打开的打开文件

时间:2014-02-01 15:40:07

标签: c# .net

在下面的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释放对象(包括实例成员)的顺序不可预测。

但是,如果符合以下条件,上面的代码肯定会引发异常(我测试过它)。

  1. 客户端开发人员忘记直接调用Dispose()
  2. 终结器调用了Dispose(false)
  3. 该流尚未处理
  4. 因此File.Delete()将失败并抛出System.IO.IOException异常。

    所以我的问题是, 确保流关闭和文件被删除的正确方法是什么? (即使开发人员忘记手动处理对象) 显然访问Stream成员(在处理== false时)是不安全的,所以必须有办法。

    请注意 FileOptions.DeleteOnClose不是选项。这就是动机:我有一个类似Open的和Close的文件类,并且在方法边界使用文件(即读取数据),我不希望在实际使用结束之前删除文件。

    参考 Essential C# 5.0

    谢谢, 奥菲尔

1 个答案:

答案 0 :(得分:0)

为什么不实施推荐(由Microsoft)模式

// When implementing Dispose, mark it my implementing 
// IDisposable interface. It make you code more readable,
// allow to put using(...) {...}  etc.
class Foo: IDisposable {
  FileInfo File; // <- class, not struct
  Stream Stream; // <- class, not struct

  ...

  // Just useful thing, esp. while debugging
  public Boolean IsDisposed {
    get;
    private set;
  }

  // Since Foo is not a sealed class be ready that
  // it could be inherited: "protected virtual"
  protected virtual void Dispose(bool disposing) {
    // .Net often let you call Dispose many time, inc. on disposed instances; 
    // The same should do we
    if (IsDisposed)
      return;

    // You can access classes (not structs) in "if (disposing) {...}" only
    if (disposing) {
      if (!Object.ReferenceEquals(null, Stream))
        Stream.Dispose();

      if (!Object.ReferenceEquals(null, File))    
        File.Delete(); 
    }

    IsDisposed = true;
  }

  // MS recommendation
  public void Dispose() {
    Dispose(false);
    GC.SuppressFinalize(this);
  }

  // No finalizer here: finalizer just make you potential error
  // (resourse leak or Access Violation) unstable and so harder
  // to detect and correct.
}

每当开发人员想要使用该类时,他/她就会简单地使用

using (var foo = new Foo(...)) {
  ...
}