【问题标题】:Exception in Destructor (c#)?析构函数(c#)中的异常?
【发布时间】:2012-04-11 18:41:53
【问题描述】:

我有这门课:

public class TempFileRef
    {
        public readonly string FilePath;

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

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

问题:

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

1) 它会破坏 F-Queue 中的其他最终确定吗?

2) 我会用TryCache 包装它 - 我会NEVER 知道有错误

3) what 我应该在这里做吗?

编辑

基于"if I **forget** to call the Dispose method - so the GC will do it eventually.... it is better later then never..."MSDN 模式。所以我的问题是特别是关于 Finilize(析构函数)中的异常

【问题讨论】:

  • 我会称它为“Finalize method”,而不是“析构函数”,尽管它使用析构函数语法。
  • @UweKeim - C# 引用称它们为析构函数。

标签: c# exception .net-4.0 garbage-collection destructor


【解决方案1】:

这实际上取决于.NET框架

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

如果 Finalize 或 Finalize 的覆盖抛出异常,并且运行时不是 由覆盖默认值的应用程序托管 策略,运行时终止进程并且没有活动的 try-finally 块或终结器被执行。这种行为确保过程 如果终结器无法释放或销毁资源,则完整性。

.NET 1 相比,只有终结器将被终止,您的应用程序将继续运行:

如果 Finalize 或 Finalize 的覆盖引发异常,则 运行时忽略异常,终止该 Finalize 方法,并且 继续最终确定过程。

您实际尝试做的是实现IDisposable 模式,因此将此工作留给完成程序,而是在程序上称为Dispose 中进行。

【讨论】:

    【解决方案2】:

    来自MSDN

    在析构函数执行期间发生的异常值得特别 提到。如果在析构函数执行期间发生异常,并且 未捕获异常,则该析构函数的执行是 终止并调用基类的析构函数(如果有)。如果 没有基类(如对象类型的情况),或者如果有 没有基类析构函数,则异常被丢弃。

    【讨论】:

    • 这可能是过时的 VS2003 / .NET 1 东西。查看其他答案。
    【解决方案3】:

    考虑实现IDisposable 接口,而不是在终结器中删除文件。

    在析构函数执行期间发生的异常值得特别 提到。如果在析构函数执行期间发生异常,并且 未捕获异常,则该析构函数的执行是 终止并调用基类的析构函数(如果有)。如果 没有基类(如对象类型的情况),或者如果有 没有基类析构函数,则异常被丢弃。

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

    【讨论】:

    • 它的 MSDN 模式基于“如果我忘记调用 Dispose 方法 - 所以 GC 最终会这样做.... 以后再也不...”。所以我的问题特别是关于 Finilize (析构函数)。 - 请看我的编辑。
    • @RoyiNamir,答案当然是不要忘记。
    【解决方案4】:

    不要使用析构函数,它不是C++,使用你应该实现的IDisposbale 接口的Dispose() 方法。从您的代码中显式调用 Dispose(),或将您的类与 using 一起使用,例如(比如说)

    using(var tempRef = new TempFileRef())
    {
        //do something here
    
    } //Dispose will be called after this line.
    

    编辑

    根据documentation

    如果 Finalize 或 Finalize 的覆盖引发异常,并且 运行时不是由覆盖默认值的应用程序托管 策略,运行时终止进程并且没有活动的 try-finally 块或终结器被执行。这种行为确保了过程 如果终结器无法释放或销毁资源,则完整性。

    换句话说:不要在 Finalizer 中调用可能失败的东西。请改用 Dispose,并确保它已被调用。

    希望这会有所帮助。

    【讨论】:

    • @downvoter:这篇文章有什么问题。和这里投票最多的答案有什么不同吗?
    猜你喜欢
    • 2017-08-16
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 2022-01-16
    • 2014-01-21
    • 1970-01-01
    • 2013-02-19
    相关资源
    最近更新 更多