2011-07-18 14 views
9

Finalizery są zawsze wywoływane przez framework .net, więc sekwencja może być poza kontrolą; nawet jeśli konstruktor się nie powiódł, destruktor nadal może zostać wywołany.C#: Jak radzić sobie z wyjątkami finalizera z biblioteki innej firmy?

Może to przysporzyć problemów, gdy takie wyjątki finalizatora pochodzą z biblioteki innej firmy: nie mogę znaleźć sposobu na ich obsłużenie!

Na przykład w poniższym kodzie, chociaż konstruktor klasy A zawsze zgłasza wyjątek i zawiedzie, finalizator A zostanie wywołany przez framework .net, również ~ B() zostanie wywołane, ponieważ A ma właściwość typu 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 
    } 
} 

Jeśli to mój kod, to jest trochę łatwiej - mogę użyć try-catch w finalizatorów, przynajmniej mogę zrobić rejestrowanie - mogę pozwolić wyjątek awarię programu, aby odkryć Błąd jak najszybciej - lub jeśli chcę "tolerować" wyjątek, mogę mieć try-catch, aby wyłączyć wyjątek i mieć zgrabne wyjście.

Ale jeśli A i B są klasami z biblioteki 3rd party, nie mogę nic zrobić! Nie mogę kontrolować wyjątku, nie mogę ich złapać, więc nie mogę go zarejestrować ani ukryć!

Co mogę zrobić?

+1

+1 Interesujący problem (aw międzyczasie podnieś pilny raport o błędach u dostawców biblioteki, która dostarcza "A" i "B"). – Ergwun

+0

^^ - Świetny punkt. Musi być prawdziwą odpowiedzią. –

Odpowiedz

2

Wygląda na to, że narzędzie innej firmy jest słabo napisane. :)

Czy próbowałeś go złapać za pomocą AppDomain.UnhandledException?

+0

Tak, robię to teraz. może zrobić rejestrowanie, ale ... nie może z wdziękiem wyjść ... – athos

0

Możesz rozważyć obsługę globalnego wyjątku dla swojej aplikacji. Nie wskazują jeśli robisz ASP.NET, WinForm, MVC, itp, ale tu jest jeden dla aplikacji konsoli:

.NET Global exception handler in console application

W ASP.NET, można użyć pliku global.asax złapać nieobsługiwane wyjątki.

Jeśli zawsze wywołujesz GC.Collect() w swojej aplikacji, możesz spróbować zawinąć to również w bloku try-catch.

Kilka pomysłów do rozważenia.

0

Można użyć GC.SuppressFinalizer(objA) i GC.KeepAlive(objA) który zapobiegnie śmieciarza z wywołaniem Finalize na tym obiekcie, a więc przy użyciu KeepAliveobjB nie sfinalizuje ponieważ objA „który jest żywy” to wciąż ma odniesienie do niego. powinieneś jednak pamiętać o przeciekach pamięci , jeśli zapomnisz sfinalizować lub zutylizować objA we właściwy sposób.

Załóżmy jednak, że na przykład w pewnym momencie metody objA zainicjalizowano inną objectB i nie można jej poprawnie usunąć. Wtedy niestety nic nie mogę z tym zrobić.

Inną rzeczą, którą możesz spróbować, jest sprawdzenie, czy biblioteka zachowuje się inaczej, gdy jesteś w trybie Release, a nie w trybie Debug; na przykład może tylko rzucić wyjątek na finalizatorze, jeśli zostanie wywołany w trybie debugowania "to jest rodzaj pomocnika dla programistów, więc jeśli nie wywołają utylizacji lub sfinalizowania obiektu we właściwy sposób, wyjątek zostanie odrzucony podczas debugowania":

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

Jeśli tak nie jest, to myślę, że będziesz miał złe dni na zajmowanie się tą biblioteką.

+0

Przepraszam, Jordan, myślę, że nie postawiłem pytania w sposób jednoznaczny, tak, że możesz mieć nieporozumienie na ten temat. – athos

+0

@athos: Przepraszam, ponownie przeczytałem twoje pytanie i zorientowałem się, że przegapiłem fakt, że 'objA' ma wartość zerową! –

Powiązane problemy