如何在 class 上正确使用 dispose 方法

How to properly use the dispose method on a class

我正在处理一个数据库,当数据库 class 在表单关闭时与其他所有东西一起被销毁时,我需要将数据库写入文件

我目前是这样称呼它的:

class database: IDisposable
{
    List<databaseEntry> dDatabase;

    public database()
    {
        dDatabase = new List<databaseEntry>;
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
             StreamWriter sw = new StreamWriter(path);

             string toWrite;

             foreach (databaseEntry dE in dDatabase)
             {
             toWrite = dE.rfid.ToString() + " " + dE.currentArea.ToString() + " " + dE.itemName;
             sw.WriteLine(toWrite);
             }

             sw.Close();
             disposed = true;
         }
     }//destructor for database (saves database to file)

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

当我关闭打开此 class 的 windows 表单时,未调用 Dispose 方法。

这是一项作业,不允许我为此使用 SQL。

您无法控制垃圾收集器何时调用 Dispose 方法。如果要在窗体关闭时释放资源,应该在窗体关闭时手动调用Dispose方法。

这是通过监听表单的FormClosed事件实现的。

所以你会做类似的事情:

  1. 创建此方法:

    private void Form1_FormClosed(Object sender, FormClosedEventArgs e)
    {
        if(this.database != null)
            this.database.Dispose(); 
    }
    
  2. 将此行放入表单的构造函数中:

    this.FormClosed += Form1_FormClosed;
    

由于您正在实施 IDisposable,另一种解决方案是将您的数据库对象实例化包装在 using 语句中 - 一旦 Dispose 中的代码 using 语句完成。

您的用例的语法如下:

using(database db = new database())
{
    //use your db object
} //db is disposed here

编辑:

Matthew Watson 的评论让我意识到我的回答过于简单并且可能令人困惑(感谢 Matthew 的评论)。这是(大部分)真实的故事:

所有对象都有构造函数和析构函数。如果未指定,则使用默认构造函数和析构函数。

构造函数:

ClassName()

析构函数:

~ClassName()

当您使用 new 关键字时,将调用 Constructor。一旦不再有对某个对象的特定实例的引用,就可以调用 析构函数 。注意我说的是可以被称为,而不是被称为。这意味着该对象符合垃圾收集条件,并且可以在车库收集器运行时被释放。我不会在这里详细介绍,只是知道出于性能原因,车库收集器并不总是收集所有无法访问的对象。这是您想要 IDisposable 界面的关键原因之一。当您知道不再使用资源而不是等待 GC 清理资源时,您可以立即清理资源。使用流或数据库连接时,实现 IDisposable 接口是个好主意。

这里是更新的答案(用析构函数引用替换以前的 "default Dispose()" 引用)。

由于这是一项作业,我本身不会给你答案,但我会让你接近。当 database 对象的实例不再可访问时,车库收集器通常会调用析构函数 (~database)。通过实现 IDisposable 接口,您提供了一种允许车库收集器处理对象的替代方法。你是在告诉车库收集器 "I know when and how these resources need to be freed" 当不再有对对象的引用时释放这些资源。但这仅适用于调用 Dispose 方法的情况;更具体地说:

Dispose(true);
GC.SuppressFinalize(this);

这意味着"Garage collector, do not call the destructor (~database()) method, I have already handled it"。

您在此方法中应该做的是关闭您打开的所有流 (StreamWriter)。

用法:IDisposable 接口在 C# 中有一个很好的构造 using 语句。这实际上是一个 try catch 块,其中 Dispose 方法在 finally 块中调用。 StreamWriter 还实现了 IDisposable,因此您应该考虑在 database class 中实现 using 语句。示例:

using(StreamWriter writer = new StreamWriter()){
    //do stuff with writer here
}

这是您应该在表单中用于数据库的模式 class。我会让你弄清楚如何编码。