【问题标题】:c#: How to handle finalizer exceptions from a 3rd-party library?c#:如何处理来自第 3 方库的终结器异常?
【发布时间】:2011-07-18 01:50:01
【问题描述】:

Finalizers 总是被 .net 框架调用,所以序列可能会失控;即使构造函数失败,析构函数仍然可以被触发。

当此类终结器异常来自第三方库时,这可能会带来麻烦:我找不到处理它们的方法!

例如,在下面的代码中,虽然类A的构造函数总是抛出异常并失败,但A的终结器会被.net框架触发,并且调用~B()是因为A具有B类型的属性。

class Program // my code
{
    static void Main(string[] args)
    {
        A objA;
        try
        {
            objA = new A();
        }
        catch (Exception)
        {
        }

        ; // when A() throws an exception, objA is null

        GC.Collect(); // however, this can force ~A() and ~B() to be called.

        Console.ReadLine();
    }
}

public class A  // 3rd-party code
{
    public B objB;

    public A()
    {
        objB = new B(); // this will lead ~B() to be called.
        throw new Exception("Exception in A()");
    }

    ~A() // called by .net framework
    {
        throw new Exception("Exception in ~A()"); // bad coding but I can't modify
    } 
}

public class B // 3rd-party code
{
    public B() { }

    ~B() // called by .net framework
    {
        throw new Exception("Exception in ~B()"); // bad coding but I can't modify
    } 
}

如果这些是我的代码,那就更容易了 - 我可以在终结器中使用 try-catch,至少我可以做一些日志记录 - 我可以允许异常使程序崩溃,尽快发现错误 - 或者如果我想“容忍”异常,我可以使用 try-catch 来抑制异常,并优雅地退出。

但如果 A 和 B 是来自第 3 方库的类,我将无能为力! 我无法控制异常的发生,我无法捕获它们,所以我无法记录或抑制它!

我能做什么?

【问题讨论】:

  • +1 有趣的问题(同时,向提供AB 的库的供应商提出紧急错误报告)。
  • ^^ -- 好点。需要是一个实际的答案。

标签: c# exception finalizer


【解决方案1】:

听起来 3rd 方实用程序写得不好。 :)

你试过用AppDomain.UnhandledException捕捉它吗?

【讨论】:

    【解决方案2】:

    您可能希望为您的应用程序考虑一个全局异常处理程序。您没有说明您是否在使用 ASP.NET、WinForm、MVC 等,但这里有一个用于控制台应用程序:

    .NET Global exception handler in console application

    在 ASP.NET 中,您可以使用 Global.asax 文件来捕获未处理的异常。

    如果您总是在应用程序中调用 GC.Collect(),您也可以尝试将其包装在 try-catch 块中。

    只是一些需要考虑的想法。

    【讨论】:

      【解决方案3】:

      您可以使用GC.SuppressFinalizer(objA)GC.KeepAlive(objA),这将阻止垃圾收集器对该对象调用finalize,因此当使用KeepAlive 时,objB 将不会finalize,因为objA“它还活着”仍然有它的参考。但是,如果您忘记以适当的方式完成或处置objA,则应该注意内存泄漏

      但是假设 objA 在某个方法中的某个时刻已经初始化了另一个 objectB 并且它没有正确处理它,那么不幸的是我不认为你可以做任何事情。

      您可以尝试的另一件事是检查当您处于Release 模式而不是Debug 模式时该库的行为是否有所不同;例如,如果在调试模式下调用终结器,它们可能只会在终结器处抛出异常“它对开发人员来说是一种帮助,因此如果他们没有以正确的方式调用 dispose 或终结对象,调试时将抛出异常”:

      ~A()
      {
      #if DEBUG
          throw new Exception("Exception in ~A()");
      #endif//DEBUG
      } 
      

      如果不是这样,那么我认为你在处理那个库时会很糟糕。

      【讨论】:

      • 对不起乔丹,我想我的问题没有说清楚,所以你可能会对它产生误解。
      • @athos:抱歉,我再次阅读了您的问题,发现我错过了objA 为空的事实!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      相关资源
      最近更新 更多