C# 使用析构函数/终结器是否昂贵?

C# 使用析构函数/终结器是否昂贵?,c#,destructor,idisposable,finalizer,C#,Destructor,Idisposable,Finalizer,我正忙着对非确定性破坏感到困惑。在回答另一个问题时,我得到了一个建议,即析构函数/终结器(我假设在c#中也是一样的,即名为~classname()的函数)是昂贵的,并且不是必需的。但看一个使用析构函数的例子,从注释中可以看出它可能是至关重要的。有人对这一切如何结合起来提出了一些建议,我应该从代码中删除析构函数吗 再次感谢。通常,在on情况下实现析构函数很有用:当无法保证时,客户端代码将正确关闭所有资源(文件流、数据库连接等)。因此,如果客户端代码无法执行此操作,那么您将拥有代码,该代码将关闭它,

我正忙着对非确定性破坏感到困惑。在回答另一个问题时,我得到了一个建议,即析构函数/终结器(我假设在c#中也是一样的,即名为~classname()的函数)是昂贵的,并且不是必需的。但看一个使用析构函数的例子,从注释中可以看出它可能是至关重要的。有人对这一切如何结合起来提出了一些建议,我应该从代码中删除析构函数吗


再次感谢。

通常,在on情况下实现析构函数很有用:当无法保证时,客户端代码将正确关闭所有资源(文件流、数据库连接等)。因此,如果客户端代码无法执行此操作,那么您将拥有代码,该代码将关闭它,这比只打开资源要好。

如果您必须在某个时间点运行某些清理,无论是否显式执行,您只应包括终结器。在这种情况下,无论如何,您都应该有一种及时执行清理的明确方式,这应该抑制最终完成,这样“好”客户机就不会看到任何性能损失

通常,只有在对非托管资源具有直接句柄的情况下,您才需要终结器-如果您只有对另一个类的引用,而该类在资源上具有句柄(例如,
FileStream
),则应将其留给另一个类来拥有终结器

随着in.NET2.0的出现,值得编写自己的终结器的情况越来越多


终结器的性能损失是它们使您的对象的生存时间超过了它们需要的时间:在第一个GC周期中,如果它们被认为有资格收集,它们将被放入终结器队列中,并被提升到下一代,就像在GC周期中幸存的任何其他对象一样。然后,终结器将在另一个线程中运行(在某个时刻),只有这样,它们才有资格真正被收集。因此,它们不是(比如)在第一个gen1集合中被收集,而是在第二个gen2集合之前一直生活,而下一个gen2集合可能会更晚。

当您直接处理非托管资源时,您只需要完整的一次性模式。然后由调用代码来确保析构函数(几乎)从未使用过

处理托管资源(=非托管资源的间接所有权)时,析构函数无效:

class FileWrapper
{
    private FileStream fs;  // managed resource

    ~FileWrapper()
    {
         if (fs != null) 
           fs.Dispose();   // fs is already on the GC finalizer queue
    }
}
每当GC收集FileWrapper对象时,可以确定fs对象在同一批中。因此,对fs.Dispose()的调用是无用的,只测试FileStream.Dispose()的正确(允许多次调用)行为


这里唯一有用的析构函数是FileStream中的析构函数

除非这些资源有自己的析构函数,就像您的所有示例一样。是的,遗憾的是,即使是该链接的Fx4版本也没有提到SafeHandle。更大的性能损失是,可终结对象引用的任何对象在下一代都是不可收集的,这些对象引用的任何对象也是如此,或者这些对象引用的任何对象,等等。如果对象直接或间接引用了终结期间不需要的对象,则该对象不应具有终结器。相反,终结所需的东西应该封装在它们自己的可终结类中,较大的对象应该包含对该类的引用。@LukeH:不,它是安全的。它本可以被处理,但不能被收集。类型安全仍然保留在析构函数中。而且也没有比赛条件。