c#: How to handle finalizer exceptions from a 3rd-party library?
Asked Answered
I

3

10

Finalizers are always called by .net framework, so the sequence could be out of control; and even if the constructor failed, the destructor still can be triggered.

This could bring troubles, when such finalizer exceptions come from a 3rd-party library: I can't find a way to handle them!

For example, in the code below, although class A's constructor always throw an exception and fail, finalizer of A will be triggered by the .net framework, also ~B() is called as A has a property of B type.

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
    } 
}

If these are my code, it is a bit easier - I can use try-catch in finalizers, at least I can do some logging - I can allow the exception to crash the program, to discover the error asap - or if I want to "tolerate" the exception, I can have a try-catch to suppress the exception, and have a graceful exit.

But if A and B are classes from a 3rd-party library, I can do nothing! I can't control the exception to happen, I can't catch them, so I can't log it or suppress it!

What can I do?

Isom answered 18/7, 2011 at 1:50 Comment(2)
+1 Interesting problem (and in the meantime, raise an urgent bug report with the vendors of the library that supplies A and B).Redden
^^ -- Great point. Needs to be an actual answer.Abbotsen
A
2

Sounds like the 3rd party utility is poorly written. :)

Have you tried catching it using AppDomain.UnhandledException?

Amerind answered 18/7, 2011 at 2:6 Comment(0)
C
0

You might want to consider a global exception handler for your application. You didn't indicate if your doing ASP.NET, WinForm, MVC, etc, but here's one for a console application:

.NET Global exception handler in console application

In ASP.NET, you can use the Global.asax file to catch unhandled exceptions.

If you are always calling GC.Collect() in your application, you might try wrapping that in a try-catch block as well.

Just some ideas to consider.

Crenation answered 18/7, 2011 at 2:7 Comment(0)
Q
0

You can use GC.SuppressFinalizer(objA) and GC.KeepAlive(objA) which will prevent the garbage collector from calling the finalize on that object,and so when using KeepAlive the objB will not finalize because objA "which is alive" is still has reference of it. however you should then be aware from memory leaks if you forget to finalize or dispose objA in a proper way.

But suppose that the objA at some point in a method for instance has initialize another objectB and it does not dispose it properly, Then unfortunately I don't thing you can do anything about it.

Another thing you can try is to check if that library behaves differently when you are in Release mode rather than the Debug mode; for example they maybe only throw exception at the finalizer if it get called in debug mode "it kind of helper to developers so if they not call dispose or finalize the object in right way an exception will throw while debugging":

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

If that is not the case, then I think you will have a bad days dealing with that library.

Quicksilver answered 18/7, 2011 at 3:3 Comment(2)
sorry Jordan, I think I didn't put my question clearly, so that you may have a misunderstanding on it.Isom
@athos: Sorry, I read your question again and figured out that I missed out the fact that the objA is null!Quicksilver

© 2022 - 2024 — McMap. All rights reserved.