C#:如何处理来自第三方库的终结器异常?

10

终结器总是被 .net framework 调用,所以顺序可能会失控;即使构造函数失败,析构函数仍然可以被触发。

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

例如,在下面的代码中,尽管 A 类的构造函数始终抛出异常并失败,但 A 的终结器将被 .net framework 触发,同时由于 A 具有 B 类型的属性,因此 ~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
    } 
}

如果这是我的代码,那么稍微容易一些: - 我可以在finalizer中使用try-catch,至少我可以记录一些日志 - 我可以允许异常使程序崩溃,以便尽快发现错误 - 或者,如果我想“容忍”异常,我可以使用try-catch来抑制异常,并优雅地退出。
但是如果A和B是第三方库的类,我就无能为力了! 我不能控制异常的发生,我不能捕获它们,所以我无法记录或抑制它!
我该怎么办?

1
+1 жңүи¶Јзҡ„й—®йўҳпјҲеҗҢж—¶пјҢеҗ‘жҸҗдҫӣAе’ҢBеә“зҡ„дҫӣеә”е•ҶжҸҗдәӨзҙ§жҖҘй”ҷиҜҜжҠҘе‘ҠпјүгҖӮ - Ergwun
-- 很好的观点。需要是一个实际的答案。 - Ritch Melton
3个回答

2

0
你可以使用 GC.SuppressFinalizer(objA)GC.KeepAlive(objA) 来防止垃圾回收器对该对象调用 finalize 方法,因此在使用 KeepAlive 时,如果 objA 仍然引用了 objB,则 objB 不会执行 finalize 方法。但是,如果您忘记以正确的方式终止或处置 objA,则可能会出现内存泄漏问题。

但是,假设在某个方法中初始化的 objA 另外还初始化了一个 objectB,并且未能正确处置它,那么恐怕您无法对此进行任何处理。

另一件你可以尝试的事情是检查该库在Release模式和Debug模式下是否有不同的行为;例如,它们可能仅在调试模式下在终结器中抛出异常“这对开发人员来说是一种帮助,因此如果他们没有以正确的方式调用dispose或finalize对象,则会在调试时引发异常”:
~A()
{
#if DEBUG
    throw new Exception("Exception in ~A()");
#endif//DEBUG
} 

如果不是这种情况,那么我认为你在处理那个库时会遇到麻烦的日子。

抱歉,乔丹,我觉得我没有清楚地表达我的问题,所以你可能会误解它。 - athos
@athos:抱歉,我再次阅读了你的问题,发现我漏掉了objA为空的事实! - Jalal Said

0
你可能想为你的应用程序考虑一个全局异常处理程序。你没有说明你是在做ASP.NET、WinForm、MVC等,但这里有一个控制台应用程序的全局异常处理程序: .NET Global exception handler in console application 在ASP.NET中,你可以使用Global.asax文件来捕获未处理的异常。
如果你总是在你的应用程序中调用GC.Collect(),你也可以尝试将其包装在try-catch块中。
这只是一些值得考虑的想法。

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