我需要在我的对象中实现dispose或finalize吗?

4

长期以来,我让垃圾收集器做它的魔法,从我的责任中解脱出来。

可悲的是,它从未成为问题......所以我从未对这个主题考虑过第二次。

现在当我想到它时,我真的不明白“dispose”函数到底是什么,以及应该如何实现它。

同样的问题也适用于finalize...

最后一个问题... 我有一个类pictureManipulation:当我需要保存/调整大小/更改格式...我启动该类的新实例使用它的对象,然后...让垃圾收集器杀死该实例

class student
{
   public void displayStudentPic()
   {
      PictureManipulation pm = new PictureManipulation();
      this.studentPic = pm.loadStudentImage(id); 
   }
}

Class Test
{
  student a = new Student();
  a.displayStudentPic();
  // Now the function execution is ended... does the pm object is dead? Will the GC will kill it?
}

通常情况下,如果您使用的任何对象实现了 IDisposable 接口,您应该实现它。或者如果您正在使用 P/Invoke。 - Powerlord
3个回答

4
关于你的class Student

我需要一个Dispose()吗?

假设Picture类是IDisposable: 是的。因为学生对象“拥有”studentPic,这使它负责清理它。最小实现:

class Student : IDisposable
{
   private PictureClass studentPic;
   public void Dispose()
   {
      if (studentPic != null)
        studentPic.Dispose();
   }
   ...
}

现在你可以像这样使用一个学生对象:

void Test
{
  using (Student a = new Student())
  {
     a.displayStudentPic();    
  } // auto Dispose by using() 
}

如果您不能/不使用using(){}块,则在完成后调用a.Dispose();即可。
但请注意,更好的设计是避免将图片对象放在学生对象中。这会引发一系列责任链。

我需要一个终结器吗?

不需要。因为当学生对象被收集时,它的studentPic对象保证在同一运行中被收集。终结器(析构函数)是无意义的,但仍然很昂贵。

很棒的答案,有助于理解第一步... 理论非常重要,但我总是觉得第一步最难 :) - Asaf

3

只有当你的类型持有一些非托管资源(如DB连接、文件句柄等)或者持有实现了IDisposable接口的对象时,才需要实现Dispose方法。下面是在实现标准Dispose模式时应该考虑的几个要点:

  • 如果你的对象不持有任何IDisposable对象或非托管资源(例如DB连接),那么你根本不需要实现IDisposable或finalizer。
  • 如果你的对象持有IDisposable对象的引用,则在Dispose方法中调用这些对象的Dispose()方法。
  • 如果你的对象不持有任何非托管资源,则不需要实现finalizer。除非你已经实现了finalizer,否则垃圾回收器不会尝试在对象上进行终结操作(这会影响性能)。
  • 如果你的对象持有非托管资源,请在finalizer中清理它们,而不需要重新编写在Dispose(bool)方法中已经存在的任何清理代码。

+1:@Asaf:“托管资源”=任何普通的 .Net 对象(可能是你编写的,也可能不是),它没有一个“句柄”来指向文件、数据库或其他存在于你运行的程序之外的“事物”。 - Binary Worrier
@Binary:我认为Managed-resource == __确实__具有对某些东西的(间接)句柄。 - H H
@Henk:“托管资源”= 垃圾回收器需要关注的内容。不是吗? - Binary Worrier
@Binary,我的最佳理解:Managed-resource == 间接/嵌套的非托管资源。请参考此答案中的第二个要点。 - H H
@Henk:看起来我是少数派,似乎没有一个明确的“托管资源”定义,但共识似乎遵循您的定义。我向您道歉并纠正我的错误 :) - Binary Worrier
+1:现在在阅读了Henk Holterman的答案并看到了一个非常简单的例子之后,我可以理解您的指导。谢谢Asaf。 - Asaf

1

如果对象持有除对象本身内存之外的资源,则需要注意对象的释放。

例如,如果您的对象抽象了一个文件,则必须在文件被释放时控制它,否则会出现非常糟糕的情况:您的应用程序已经使用完它,但它仍然被锁定,直到GC处理您的对象。

要了解如何正确处理它,请阅读有关dispose和finalize以及using(){}子句的手册。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接