2011-11-11 13 views
7

Wprowadzając nowe typy wyjątków, zawsze jestem pewien, ale nie wiem, jak to zrobić poprawnie. Czy istnieje wspólna konwencja? Jak ty to robisz?Jak nazywasz i organizujesz wyjątki?

Jestem zainteresowany zakresu je organizować (Należy je przechowywać w jednostce są one wykorzystywane? Czy jednostkę na poziomie komponentu? Poziomie pakietu? Aplikacji?)

ten wpływa również nazewnictwa. Ile kontekstu uwzględniasz? Czy lepiej uczynić je bardzo specyficznymi (jak EPersonIDNotFoundError), czy też spróbować uczynić je możliwymi do ponownego użycia (jak ENotFoundError)?

A co z przyrostkiem "Błąd" - kiedy należy go dodać i kiedy go opuścić? Nie widzę logiki, np. w Classes.pas:

EWriteError = class(EFilerError); 
    EClassNotFound = class(EFilerError); 
    EResNotFound = class(Exception); 
+0

Myślę, że dobrze jest organizować wyjątki według wagi i paczki. Według stopnia ważności, np. oddzielne wyjątki sprawdzania poprawności od błędów ładowania/zapisywania danych. Instancja wyjątku może zawierać bardziej szczegółowe informacje na temat okazji, w jakich się pojawił. – too

+1

To nie jest pytanie ... Zbyt wiele pytań naraz, z potencjalną debatą (trolling?). IMHO to nie pasuje do celu SO. –

+0

@Arnaud Cóż, pozwól mi spróbować odpowiedzieć na to. Ponieważ naprawdę doceniam dane wejściowe. –

Odpowiedz

6

Jedynym konwencja znam, ma poprzedzić je E. Tak naprawdę nie zastanawiałem się zbyt wiele w przeszłości, ale teraz myślę o tym, wydaje mi się, że zarówno Error i Exception są powszechnie używane jako postfiksy. Jeśli je miksujesz, powiedziałbym, że Exception odnosi się do czegoś, co nieoczekiwanie dzieje się nie tak, jak połączenie, które jest zepsute, lub pliku, który okazuje się nieczytelny, podczas gdy błąd odnosi się bardziej do błędnego wprowadzenia, na przykład numer był oczekiwano, ale ktoś wpisał tekst.

VCL wydaje się przestrzegać pewnych konwencji zbyt, ale wydaje się, aby dodać postfix tylko wtedy, gdy nie będzie jasno i błędów bez niego, na przykład

EConvertError, EMathError, EVariantError

vs

EAccessViolation, EInvalidPointer, EZeroDivide

ten ostatni opisuje sam błąd, w którym pierwsza lista mieć postfix celu wskazania błędu w danym procesie i podmiot.

Te przykłady znajdują się w SysUtils, może możesz tam zajrzeć, ponieważ zawiera wiele klas wyjątków, a także klasy bazowe dla jeszcze większej ilości wyjątków. Bardzo niewiele z nich kończy się w Exception, z wyjątkiem pewnych bardzo specyficznych błędów, które rzeczywiście masz nadzieję nigdy nie spotkać, takich jak EHeapException i ESafecallException.

+0

Dobra uwaga dotycząca pomijania "Błąd", gdy komunikat o błędzie bardzo dobrze przenosi stan awarii. Czy miksujesz "wyjątki" i "błąd"? –

+1

Rzadko używam "błędu", chociaż mogę od teraz, ponieważ to pytanie skłoniło mnie do myślenia o tym. Ale zwykle nie wprowadzam wielu typów wyjątków. Zwykle tworzę kilka podstawowych wyjątków na poziomie aplikacji i (ponownie) używam wielu istniejących wyjątków. Jeśli nie uda mi się przekonwertować pewnej wartości, z przyjemnością wykorzystam do tego funkcję EConvertError, a moja własna implementacja list/array/collection może łatwo ponownie użyć EListIndexError niezależnie od tego, jak się nazywa. Z pewnością nie tworzę oddzielnych wyjątków dla każdego pola, które nie zostało znalezione. – GolezTrol

1

Podczas tworzenia nowego wyjątku nadaję mu szeroką aplikację. Zaczynam od najbardziej szczegółowego błędu do najbardziej ogólnej, takiej jak klasa (wyjątek) i odpowiednio je nazywam.

W twoim przykładzie użyłbym EPersonIDNotFoundError, ENotFoundError, Exception.

To naprawdę zależy od tego jak wiele szczegółów chcesz z komunikatów o błędach i co umieścić w swoim dzienniku (jeśli trzymać dziennik błędów)

1

Normalnie do prostych zastosowań można uciec z Exception.Create ('Komunikat o błędzie'). Tam, gdzie wyjątki stają się potężne, można wykryć rodzaj reakcji wymaganej przez patrzenie na klasę. Delphi robi to już w procedurze przerwania, która podnosi wartość w programie EAbort. E-mail jest "wyjątkowy", ponieważ nie powoduje "błędu" jako takiego, tj. Jest rodzajem "cichego" wyjątku. Możesz użyć tej akcji specyficznej dla klasy, aby sprawdzić wyjątek i zrobić różne rzeczy. Możesz stworzyć EMyWarning, EMyVeryNastyError itp., Każdy pochodzący z podstawowego typu Exception.

Co więcej, można zdefiniować nową klasę wyjątków, aby przenieść więcej informacji do punktu, w którym wyjątek został uwięziony. Na przykład z kodem (nie sprawdzone):

EMyException = class(Exception) 
    constructor Create(const AErrorMessage : string; AErrorCode : integer); reintroduce; 
PUBLIC 
    ErrorCode : integer 
end; 

constructor EMyException.Create(const AErrorMessage : string; AErrorCode : integer); 
begin 
    inherited Create(AErrorMessage); 
    ErrorCode := AErrorCode; 
end; 

Masz teraz możliwość ustawienia „ERRORCODE” kiedy podnieść wyjątek i masz to dostępne, gdy wyjątek zostanie złapany. Wyjątki są dość potężne.

+0

Naprawdę nie jest to odpowiedź na pytanie, ale dobra demonstracja, dlaczego w pierwszej kolejności należy dziedziczyć z wyjątków. I uwielbiam EAbort. :) Możesz przerwać tak wiele rzeczy. Na przykład, przerwij publikację rekordu, podnosząc konto EABort w OnBeforePost i wiele takich podobnych przerw. Używam go także do przerywania skomplikowanych operacji. – GolezTrol

1

Jakiego zakresu można je uporządkować?

Użyj jednej jednostki dla całej aplikacji, w której próbujesz dopasować się do najbardziej ogólnych wyjątków. Cała reszta trafia do jednostki, w której wyrzucany jest wyjątek. Jeśli potrzebujesz tych wyjątków w innych jednostkach, przenieś je do wspólnej jednostki używanej przez podsystem, nad którym pracujesz.

Co powiesz na nazywanie?

Spróbuj ustawić jeden lub dwa poziomy "ogólnych" wyjątków, takich jak ENotFoundError. Umieść je w pliku globalnym aplikacji. Nie próbuj zbyt mocno, aby generalizować, ponieważ nie możesz wiedzieć, jaki wyjątek przyjdzie później, wymagając od Ciebie zmiany wszystkiego. Twórz wyspecjalizowane wyjątki na poziomie jednostki dziedzicząc z globalnych.

Co z postfiksem "Błąd"?

Przestań o tym myśleć. Add it. Chyba, że ​​brzmi to głupio.

+2

Jeśli kod używa dużo interfejsów, zadeklarowałbym wyjątki w jednostce, która deklaruje interfejsy, a nie w kodzie implementacyjnym, który je rzuca – mjn

+1

@mjn Absolutnie. W przeciwnym razie użytkownicy interfejsu nie mogą wykonywać konkretnych sprawdzeń w stosunku do klas wyjątków bez uzyskania zależności od implementorów ... –