W dniu 2013-03-26 19:29, Piotr Rezmer pisze:
Akurat to jest łatwe, ten nadrzędny z inną obsługa umieszczasz jako
pierwszy na liście.
Typowy przykład:
except:
....
on e: EAbort do raise;
on e: Exception do
begin
logger.LogException(e);
Abort();
end;
end;
> Ale to
> może tez świadczyć o nieodpowiedniej hierarchii wyjątków. W tym
> konkretnym przypadku wyjątki generuję przy pobieraniu danych adresowych
> klienta. Wyjątkiem nadrzędnym jest coś w stylu EAddressException. Jednak
> dziedziczą z niego wyjątki EZipCodeMissingException ( i to wydaje się w
> porządku) a także EGetAddressDataException (i to chyba moja pomyłka.
> Wyjątki warstwy transportowej powinny być podpięte do innego przodka).
>
No cóż, dobra hierarchia wyjątków jest dobra ;-)
>> Lub wydelegowanie obsługi wyjątku do funkcji, która już sobie
>> tradycyjnie rozpozna typ wyjątku.
>>
> Przyznam się że deklaratywne podanie typu obsługiwanego wyjątku jakoś
> wydaje mi się bardziej koszerne. Fajnie byłoby też gdyby Delphi
> kontrolowało wyjątki wyrzucane przez wszystkie linie kodu metody i
> dodawałoby wyjątki do sygnatury metody, a następnie wymuszało użycie
> try/except lub dalsze przekazywanie wyjątku tak jak się to odbywa w
> Javie. Wtedy trudno przegapić jakieś mniej oczywiste wyjątki.
Tyle że ten mechanizm w Javie jest jak miecz obosieczny: często
deklaruje się funkcje rzucają generyczny 'Exception', co potem jes mało
użyteczne, a bywa uciążliwe.
>>
>> BTW do procedury obsługi wyjątku niekoniecznie musisz przekazywać
>> wyjątek, aktualny wyjątek możesz wziąć z System.ExceptObject. Przydaje
>> się to przy generycznej obsłudze typu:
>>
>> try
>> ...
>> except
>> HandleException(...);
>> end;
>
> A to jest zmienna globalna? Co z kodem równoległym? Nie jest jednak
> bezpieczniej przekazać E: Exception?
>
To jest funkcja. Zwraca aktualny wyjątek ze stosu wyjątków
(implementowany jako linked-list). A wskaźnik na stos jest w TLS
(thread-local storage), więc każdy wątek ma swój stos.
Jak bardzo chcesz to można sobie spokojnie w każdym momencie sczytać
cały stos wyjątków, razem z innymi danymi, np. adresami ich wystąpienia.
"E: Exception" jest łatwiejsze, ale nie zawsze dostępne, np
Application.HandleException() go nie dostaje.
>>
>> lub:
>>
>> try
>> ...
>> except
>> if not HandleException(...) then raise;
>> end;
>>
>> Innym zastosowaniem takiej procedury HandleException() może być zamiana
>> oryginalnego wyjątku niskopoziomowego na wyjątek biznesowy,
>> HandleException() może rzucić biznesowym wyjątkiem który poleci dalej
>> zamiast orginalnego.
> Z tym że dokładnie to samo można zrobić z klasycznym try/except/on/raise
> EAnotherException.Create()
Można.
Tyle że ogólne handlery, takie jak Application.HandleException(), czy
moje TAThread.HandleException() zazwyczaj nie mają takiego luksusu.
Po drugie rzuconym obiektem wcale nie musi być coś dziedziczącego po
Exception. A wtedy tradycyjne on 'E: Exception do' nie wyłapie wyjątku.
Zresztą nie traktuj moich słów jak ewangelii, że tak koniecznie trzeba
;-) Po prostu pokazuję możliwości.
Kolejna możliwość rozwiązania Twojego problemu:
except
on E: Exception do
begin
if E is EIOError then
....
else
if (E is EBusinessError) and Assigned(FOnError) then
FOnError(Self, E as EBusinessError)
else
Application.HandleException(Self);
end;
end;
>>
>> Jeszce inne zastosowanie to takie że HandleException() loguje wyjątek,
>> ale dalej rzuca EAbort (Abort()), czyli wyjątek który zwinie stos, ale
>> nie będzie skutkował dalszymi komunikatami czy oknem dialogowym.
>
> A jak używam Eurekalog, to czy ma sens używanie handleException() ? W EL
> można oczywiście wyłączyć okna dialogowe z wyjątkiem.
Nie wiem co robi EL, pewni tylko loguje wyjątek. Jeśli taka obsługa Ci
wystarczy, to czemu nie.
Ale logowanie nie zawsze wystarcza...
Zresztą EL pewnie podłącza się do Application.OnException, co działa
dobrze, ale tyko dla VCL, i kodu który używa Application.HandleException().
--
Arivald