在部署时将类保存到磁盘:我的代码是否有错误?

时间:2010-09-30 16:52:17

标签: c# idisposable destructor

我正在尝试创建一个简单的类,它在不再使用时将自身序列化为磁盘。我现在的代码(见下文)。我现在的代码似乎有效,但我对自己的知识并不完全自信,所以我想知道是否有其他人发现此代码存在任何重大问题。

void IDisposable.Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

~MyClass()
{
    Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
    if (!this.disposed)
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, this);
        byte[] output = Dostuff(ms);
        File.WriteAllBytes(DBPATH, output);
    }
    this.disposed = true;
}

3 个答案:

答案 0 :(得分:6)

这可能会奏效 - 但我不会这样做。通过这样做,您可能会在终结线程中执行潜在危险的代码。如果出现任何问题,你的状况会很糟糕......

处理应该除了处理您的资源之外什么都不做。我强烈建议将其移至另一个方法,并使其成为对象API的一部分,而不是依赖IDisposable来处理您的处理。

答案 1 :(得分:5)

几乎不可能正确地编写终结器,而在一个中完成这种工作只是一个灾难的处方。更不用说它会破坏性能并且无法调试。终结者的规则1是不要使用它们。规则2(仅限高级用户)不使用它们,除非您确定必须这样做。

如果只是为了一个有趣的爱好项目,那么没有真正的伤害,它可能会运作得很好,但如果我在生产代码库中看到过类似的东西,我会哭。

如果你确实想做这样的事情,那么我会把它作为一个显式调用,并且只是在调试期间使用终结器来捕获未调用显式方法的情况,例如。

class MyClass
{
    private bool dirty; // set this whenever the object changes

    ~MyClass 
    {
        if (this.dirty) 
        {
            Debug.Fail("Object was not saved.");
        }
    }

    public void Save()
    {
        if (this.dirty)
        {
            // TODO: do the save
            this.dirty = false;
        }
    }
}

答案 2 :(得分:4)

首先,我认为你的设计相当薄弱,因为你的班级违反了Single Responsibility Principle。更为可取的是区分两个职责:可序列化实体以及将此实体保存/读取到持久存储/从持久存储中读取。在大多数情况下,可序列化的实体是lightwait,而finalizable类则不是。

其次,你应该避免在终结器中使用复杂的逻辑。例如,将可序列化类保存到Storage.Dispose方法的持久存储中会更好。并且从终结器方法只将警告写入日志文件,因为它显示不适当的类存储使用情况:

[Serializable]
public class MySerializableClass {
}

public sealed class MyStorage : IDisposable {

  ~MyStorage()
  {
     Dispose(false);
  }


  public void Dispose()
  {
     Dispose(true);
     GC.SuppressFinalize(this);
  }


  void Dispose(bool disposing)
  {
     if (!this.disposed)
     {
        if (disposing)
        {
          //We can access to all managed resources
          using (var ms = new MemoryStream())
          {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, mySerializableClass);
            byte[] output = Dostuff(ms);
            File.WriteAllBytes(DBPATH, output);
          }
        }
        else
        {
           //Inappropriate storage usage!
           //We can't guarantee that mySerializableClass object would
           //properly saved to persistant storage.
           //Write warning to log-file. We should fix our code
           //and add appropriate usage!
        }
    }
    this.disposed = true;
 }

}