C#析构函数的示例用法

4

我正在阅读有关C#中析构函数的内容,但我很难找到一个合适的使用案例。

能否提供一个带有解释的用法示例?

非常感谢。

更新
书中的代码示例实现了析构函数和Dispose()方法,请参考书中的此代码片段。

class MyClass
{
    bool disposed = false; // Disposal status
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~MyClass()
    {
        Dispose(false);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposed == false)
        {
            if (disposing == true)
            {
                // Dispose the managed resources. Factored Dispose

            }
            // Dispose the unmanaged resources.

        }
        disposed = true;
    }
}

马尔科


这是一篇相当不错的文章,链接为http://www.devx.com/dotnet/Article/33167/0/page/2。 - Aaron McIver
6个回答

8

最终器现在非常少使用。当您直接访问本机资源时,它们曾经是必需的,但现在通常应该使用SafeHandle

Joe Duffy有一篇关于这个问题的优秀文章,比我自己写的要详细得多 - 所以去读一下吧 :)

术语方面的一个快速说明:C#规范的ECMA版本将它们称为最终器;Microsoft规范一直将它们称为析构函数,并继续这样做。


你现在在哪里?在火车上吗? =P 我看到你在 Meta 上发布的日程表。当你因为日程表得到赞时,我笑了很多!呵呵呵...不过,我必须考虑时区,所以你现在应该在家,不是在看电视,而是在 SO 上发帖子!=P 无论如何!祝你晚上愉快!=) - Will Marcouiller
@Will:在发布和玩PixelJunk Monsters之间交替 :) - Jon Skeet
多么精彩的文章 - 谢谢!很高兴看到由于SafeHandle的实现,我很少需要使用它。 - Marko
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - codingbiz
@codingbiz:不,我认为我的回答非常清楚,SafeHandle意味着你应该很少使用析构函数... - Jon Skeet
显示剩余3条评论

2

它们是终结器,而不是析构函数。通常用于清理非托管资源 - 如果您编写了自己的文件类,则需要使用终结器来清理本机文件句柄。


虽然有时候人们会质疑“析构函数”是否应该称为“析构器”,但在2007年底发布的C#语言规范第3.0版中,将这个方法称为析构函数。- Apress Illustrated C# 2008。自那以来是否有所改变?此外,一些示例代码会非常棒! - Marko
好的,忽略我的示例代码注释,看起来很少有用处! - Marko

1

在C#中,很少需要使用终结器,添加终结器会导致垃圾回收器清理垃圾所需的时间更长,因为需要运行额外的传递来运行终结器。相反,通常应该使用IDisposable模式。

终结器的一个示例用法是,如果您怀疑资源泄漏,可以在调试时使用它来检查对象在被垃圾回收之前是否正确调用了Dispose。如果在调用Dispose之前就调用了持有非托管资源的对象的终结器,则可能表明存在资源泄漏。但由于终结器可能永远不会被调用,因此不应包含任何应用程序关键逻辑。


有趣的是,我正在阅读的书中的代码实现了Dispose和析构函数(实际上调用了Dispose(false))。 - Marko
@Marko在.NET 2.0引入SafeHandle之前,这种模式很常见。现在它已经被弃用了。 - CodesInChaos
谢谢你们俩,我已经加入了书中的示例代码作为参考 :) - Marko

1

你知道什么是析构函数吗?C#中有这个东西。

  • IDisposable模式,用于确定性销毁
    在不再需要句柄时有用。因此,它们现在被关闭,而不是GC决定收集对象的时间,这可能会晚得多或根本不会收集。
    或者在纯托管代码中告诉对象从对象图中删除自身,取消订阅事件等。
    通常与using语句一起使用
  • 终结器几乎没有用处。它在未知时间运行,可能根本不运行...
    我唯一使用它的原因是提醒我忘记调用Dispose释放资源
    虽然它具有C++析构函数的语法,但我不认为它是C++析构函数的等价物。我更喜欢将Dispose()视为析构函数。
  • Critical finalizationSafeHandle,用于处理本地资源

我认为现代代码应该拥有一个私有的SafeHandle并在自己的Dispose中调用它的Dispose方法,而不是使用您发布的模式。


0

IDisposable 接口提供了一种作为析构函数/终结器使用的方法。

我的意思是,您可以实现 IDisposable 接口以释放对象正在使用的资源。正如其他人所说,这与传统的析构函数不同,因为 Dispose() 方法不会直接由您调用,而是由托管代码在一段时间后处理您的对象时调用。


不,它们非常不同。Dispose由其他代码显式调用,而析构函数/终结器是由垃圾回收器在非确定性情况下调用的。 - Jon Skeet
嗨,威尔:给你点赞!你第一个到达那里了。 - n8wrl
@Will:我正在忙着输入评论,这需要一定的时间 :) 我理解那些只点踩不留言的投诉,因为我也经常遭受这种待遇... - Jon Skeet
你回答的问题在于措辞上暗示了 IDisposable.Dispose() 和“析构函数/终结器”是同一回事,这显然不正确。 - Timwi
@Jon:但是当我实现 IDisposable 接口时,假设我正在编写自己的 Connection 类,并将 DbConnection 作为私有成员。当我关闭连接时,我可以调用 Dispose 方法,以便相应地处理我的 DbConnection 私有字段。这不是正确的吗? - Will Marcouiller
显示剩余3条评论

0
C#并没有像你想象的那样拥有“析构函数”。在.NET的垃圾回收器中,当你的类超出范围时,并不会立即进行对象回收。
我认为你更感兴趣的是IDisposable模式。这是一种确定性的方式,用于清理对象使用的资源。
此外,.NET类可以拥有“终结器”,当对象被回收时执行。它可以用于在原始调用者忽略dispose的情况下调用dispose。
但是,在类中实现终结器会将其排队进行特殊的GC处理,并可能对性能产生影响。

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