Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 终结器和IDisposable_C#_Dispose_Idisposable_Finalizer_Garbage Collection - Fatal编程技术网

C# 终结器和IDisposable

C# 终结器和IDisposable,c#,dispose,idisposable,finalizer,garbage-collection,C#,Dispose,Idisposable,Finalizer,Garbage Collection,根据文档(MSDN:),很明显在实现终结器时应该使用IDisposable模式 但是,如果实现IDisposable(以便提供处理对象的确定方法),并且没有任何非托管资源需要清理,那么是否需要实现终结器 在我看来,如果类只有托管资源,而您不调用Dispose,那么托管资源将被GC自动清理,因此无需实现终结器。我错了吗 另外,如果我正在使用Dispose方法清理事件处理程序呢。由于Dispose不会自动被GC调用,我是否应该实现一个终结器,以确保EventHandler不被激活?除非您有非托管资源

根据文档(MSDN:),很明显在实现终结器时应该使用IDisposable模式

但是,如果实现IDisposable(以便提供处理对象的确定方法),并且没有任何非托管资源需要清理,那么是否需要实现终结器

在我看来,如果类只有托管资源,而您不调用Dispose,那么托管资源将被GC自动清理,因此无需实现终结器。我错了吗


另外,如果我正在使用Dispose方法清理事件处理程序呢。由于Dispose不会自动被GC调用,我是否应该实现一个终结器,以确保EventHandler不被激活?

除非您有非托管资源,否则不应该添加终结器

拥有托管的可支配资源而不是非托管资源的类应该实现完整的
Dispose
模式,但不具有终结器


如果类不是
密封的
,它应该在其
Dispose()
方法中调用
GC.SuppressFinalize(this)
,以防继承的类添加终结器。

如果您只有托管资源,那么您根本不需要实现IDisposable。IDisposable用于清理GC域之外的内容,如本机句柄、数据库连接等

如果您的控件包含实现IDisposable的控件,并且它们必须释放本机资源,那么您仍然需要实现IDisposable模式,并给您的子控件一个释放的机会


在终结器中调用Dispose()的原因是作为最后手段,如果对象未正确处置,GC将做最后的努力。

是的,如果您只有托管资源,则在垃圾收集发生时,GC将清理这些资源(并且没有任何指向它们的活动引用)

但是在这种情况下,为什么需要在您的类型上实现IDisposable?我的意思是,你似乎认为,在你的情况下,不处理你的对象不是一个大问题,那么为什么会有人处理它们?

您还应该注意到,在使用终结器时,垃圾收集会导致性能下降:任何带有终结器的对象都会逃逸第一次GC传递,如果这些对象的生命周期很短,这将大大降低GC效率


在应该清理对象的第一次垃圾收集期间,为了执行终结器,它不会清理。然后,GC会认为该对象是长寿命的,即使它已经被清除。

不,如果您有一个实现IDisposable的类(即如果您正确实现了该模式,并且您只有可处置的托管资源),则无需实现终结器


(如果这样做,它实际上会影响对象的生存期,因为带有终结器的对象会被添加到GC中的终结队列中,并且可能比它们需要的时间更长—如果对象很大,这可能是一个问题。)

我从未需要实现终结器。如您所知,它使对象有机会在GC之前执行它需要的任何操作。应释放dispose方法中的所有资源

  • 不,您是对的,如果您的对象包含一个包含非托管资源的对象,那么您应该实现IDisposable,这样您就可以在Dispose上调用它的Dispose,但您不需要Finalizer,因为它的Finalizer将处理这一问题

  • 事实上,试图在决赛选手中对决赛选手进行任何操作都是令人担忧的,因为决赛选手将运行的顺序并不确定,因此如果您尝试这样做,您可能会遇到一些讨厌的bug

  • 通常,最好让一个类包含1或0个非托管资源。如果它有一个非托管资源,则它应该具有处理它所需的尽可能少的其他状态(即没有其他可处置成员)。安全手柄是一个很好的处理方法。如果一个类需要处理多个非托管资源,它应该通过这些处理程序类来处理这些资源。然后一个决赛者&IDisposable变得容易了;要么您在这两种情况下都有要处理的唯一非托管资源(如果调用了dispose,则禁止使用finalizer),要么您只需要IDisposable


  • 因为直接处理非托管资源的情况相对较少,所以很有可能您永远不必编写定稿器(我想我曾经在实际代码中这样做过一次)。因为明智的人在处理非托管资源的类中不会做太多其他事情,所以整个Dispose(bool)工作也没有必要。

    如果继承的类也会添加非托管资源呢?@Henk:这就是为什么它会添加终结器。(和覆盖
    Dispose(bool)
    )@Henk:Huh?你在说什么
    SuppressFinalize
    由非虚拟的
    Dispose()
    方法调用,在任何情况下都应该调用。如果派生类添加了非托管资源,它应该在
    Dispose(bool)
    中清理它,并添加一个调用
    Dispose(false)
    的终结器。如果调用了普通的
    Dispose
    方法,则非托管资源将被清除,因此终结器应该被抑制。我认为您应该在可终结类(无论是否密封)中的Dispose()中调用GC.SuppressFinalize(this)。也就是说,我还是要将其密封起来,而不使用Dispose(bool)反模式。@Jon:如果该类是密封的,并且没有终结器,那么调用
    SuppressFinalize
    就没有意义了。非托管资源必须由终结器清理(和Dispose;请参见模式)除了SafeHandle之外,任何新编写的类持有非托管资源的原因是什么?显然,早于SafeHandle的类必须这样做,但新编写的类是否有这样做的空间?@Rajah:我们的答案并不矛盾。然而,我是对的;见和@Rajah:a