C #: Как обрабатывать исключения финализатора из сторонней библиотеки? - PullRequest
9 голосов
/ 18 июля 2011

Финализаторы всегда вызываются .net framework, поэтому последовательность может быть неуправляемой;и даже если конструктор потерпел неудачу, деструктор все еще может быть запущен.

Это может вызвать проблемы, когда такие исключения финализатора поступают из сторонней библиотеки: я не могу найти способ обработать их!

Например, в приведенном ниже коде, хотя конструктор класса 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 в финализаторах, по крайней мере, я могу сделать некоторую регистрацию - я могу разрешить исключение, чтобы аварийно завершить программу, чтобыобнаружите ошибку как можно скорее - или если я хочу «допустить» исключение, я могу попытаться перехватить исключение и получить изящный выход.

Но если A и B являются классами от третьегоПартийная библиотека, ничего не могу поделать!Я не могу контролировать возникновение исключения, я не могу их поймать, поэтому я не могу его зарегистрировать или подавить!

Что я могу сделать?

Ответы [ 3 ]

2 голосов
/ 18 июля 2011

Похоже, что сторонняя утилита написана плохо.:)

Вы пытались поймать его, используя AppDomain.UnhandledException ?

0 голосов
/ 18 июля 2011

Вы можете использовать GC.SuppressFinalizer (objA) и GC.KeepAlive (objA) , что будет препятствовать сборщику мусора вызывать финализ для этого объекта, и поэтому при использовании KeepAlive objB не будет завершен, потому что objA "который жив" все еще имеет ссылку на него.тем не менее, вы должны знать о утечках памяти , если вы забудете завершить или утилизировать objA надлежащим образом.

Но предположим, что objA в некоторый момент в методе дляэкземпляр инициализирует другой objectB и не удаляет его должным образом. Тогда, к сожалению, я ничего не могу с этим поделать.

Еще одна вещь, которую вы можете попробовать, это проверить, ведет себя ли эта библиотека по-другому, когда вынаходятся в режиме Release, а не в режиме Debug;например, они могут генерировать исключение в финализаторе только в том случае, если он вызывается в режиме отладки, «это своего рода помощник для разработчиков, поэтому, если они не вызывают правильное обращение к объекту или завершают его, исключение будет генерироваться при отладке»:

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

Если это не так, то, думаю, у вас будут плохие дни, когда вы будете работать с этой библиотекой.

0 голосов
/ 18 июля 2011

Возможно, вы захотите рассмотреть глобальный обработчик исключений для вашего приложения. Вы не указали, выполняете ли вы ASP.NET, WinForm, MVC и т. Д., Но вот для консольного приложения:

.NET Глобальный обработчик исключений в консольном приложении

В ASP.NET вы можете использовать файл Global.asax для перехвата необработанных исключений.

Если вы всегда вызываете GC.Collect () в своем приложении, вы можете попробовать обернуть это также в блок try-catch.

Просто несколько идей для рассмотрения.

...