析构函数中的异常(c#)?

5
我有这个类:
public class TempFileRef
    {
        public readonly string FilePath;

        public TempFileRef(string filePath)
        {
            FilePath = filePath;
        }

        ~TempFileRef()
        {
            File.Delete(FilePath);    //<== what happens if exception ?
        }
    }

问题:

如果析构函数中发生异常会发生什么?

1)它会破坏F-队列中的其他finalization吗?

2)我将使用TryCache来包装它 - 我将永远不会知道是否出现错误

3)在这里应该做些什么?

编辑

MSDN基于"如果我**忘记**调用Dispose方法 - 因此GC最终将执行它.... 比永远都好..."的模式。因此,我的问题是关于Finilize(析构函数)中的异常。


2
我会称它为“Finalize method”而不是“Destructor”,尽管它使用了析构函数的语法。 - Uwe Keim
2
@UweKeim - C# 参考文献称其为析构函数。 - H H
4个回答

15

实际上这取决于.NET框架的版本。

例如在.NET 2.NET 4中,你的应用程序将被终止。

如果Finalize或其覆盖项引发异常,并且运行时未由覆盖默认策略的应用程序托管,则运行时终止进程,不执行任何活动try-finally块或finalizers。如果finalizer不能释放或销毁资源,则此行为确保进程完整性。

相比之下,在.NET 1中,只有那个finalizer将被终止,你的应用程序将继续运行:

如果Finalize或其覆盖项引发异常,则运行时将忽略该异常,终止该Finalize方法,并继续完成终结过程。

你实际上想要做的是实现IDisposable模式,因此不要把这项工作留给终结器,在代码中调用Dispose方法来完成。


8

来自MSDN

需要特别注意的是,在析构函数执行期间发生的异常。如果在析构函数执行期间发生异常,并且该异常未被捕获,则该析构函数的执行将终止并调用基类(如果有)的析构函数。如果没有基类(如对象类型),或者不存在基类析构函数,则该异常会被丢弃。


这可能是一个过时的VS2003 / .NET 1的东西。请参考其他答案。 - Thomas Weller

6

在finalizer中删除文件时,考虑实现IDisposable接口。

需要特别注意的是析构函数执行过程中发生的异常。如果析构函数执行过程中发生了未被捕获的异常,则该析构函数的执行将终止,并调用基类(如果有)的析构函数。如果没有基类(例如对象类型)或者没有基类析构函数,则该异常将被丢弃。

http://msdn.microsoft.com/en-us/library/aa664609%28v=vs.71%29.aspx


MSDN的模式是基于“如果我忘记调用Dispose方法-那么GC最终会处理它...迟早总比永远不做好...”。所以我的问题特别涉及Finilize(析构函数)。-请参见我的编辑。 - Royi Namir
@RoyiNamir,那么答案就是不要忘记。 - Ash Burlaczenko

0
不要使用析构函数,因为它不是C++的一部分。而是应该使用IDisposable接口中的Dispose()方法,并实现该方法。从代码中显式调用Dispose(),或者像这样使用您的类:using
using(var tempRef = new TempFileRef())
{
    //do something here

} //Dispose will be called after this line.

编辑

根据文档

如果Finalize方法或其重写方法抛出异常,并且运行时不是由覆盖默认策略的应用程序托管,运行时将终止进程并且不执行任何活动的try-finally块或finalizer。这种行为确保了进程的完整性,如果finalizer无法释放或销毁资源。

换句话说:不要在Finalizer中调用可能会失败的内容。相反,请使用Dispose,并确保已调用它。

希望对您有所帮助。


1
@downvoter:这个帖子有什么问题?它与最多赞同的答案有何不同? - Tigran

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