代码之家  ›  专栏  ›  技术社区  ›  Brian

将类保存到dispose上的磁盘:我的代码有bug吗?

  •  2
  • Brian  · 技术社区  · 14 年前

    我正在尝试创建一个简单的类,当它不再使用时将自己序列化到磁盘。我现在拥有的代码(见下文)。我现在的代码似乎可以工作了,但我对自己的知识没有充分的信心,所以我想知道是否有其他人看到这个代码有任何重大的问题。

    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 回复  |  直到 14 年前
        1
  •  5
  •   Greg Beech    14 年前

    要正确地编写终结器几乎是不可能的,在一个终结器中完成这种工作只会导致灾难。更不用说它会破坏性能并且无法调试。终结器的第一条规则是永远不要使用它们。规则2(仅适用于高级用户)是不要使用它们,除非你真的确定你必须这样做。

    如果您确实想做这样的事情,那么我会将其作为显式调用,并简单地使用finalizer在调试期间捕获未调用显式方法的情况,例如。

    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
  •  6
  •   Reed Copsey    14 年前

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

        3
  •  4
  •   Sergey Teplyakov    14 年前

    首先,我认为你的设计很薄弱,因为你的班级违反了 Single Responsibility Principle . 更可取的做法是区分两种职责:可序列化实体和将此实体保存/读取到持久存储中。在大多数情况下,可序列化实体是lightwait,而可终结类不是。

    第二,应该避免终结器中的复杂逻辑。例如,最好将可序列化类保存到持久性存储中储存、处置方法。而从finalizer方法只能将警告写入日志文件,因为它显示了不适当的类存储使用情况:

    [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;
     }
    
    }