2013-05-05 12 views
30

Zawsze brakowało mi wbudowanego typu wyjątku w języku C#, który wskazywałby, że obiekt jest uszkodzony. Co rzucasz w takich przypadkach?Jaki wyjątek do rzucania na nieprawidłowy stan obiektu?

Zwykle tęsknię za tym, gdy zdaję sobie sprawę, że metoda, która ma działać na obiekcie, zakończyłoby się niepowodzeniem, gdyby obiekt miał określony stan. W takich sytuacjach często podejrzewam, że ten stan prawdopodobnie nigdy nie zostanie osiągnięty. Ale będąc w defensywie, chciałbym rzucić wyjątek na wszelki wypadek (np. Po zmianie kodu w przyszłości).

Dla argumentów metody mamy ArgumentException, więc możemy odmówić nieprawidłowe parametry. Ale dla stanu obiektu? W Javie użyłbym IllegalStateException.

Oczywiście można argumentować, że metody, które faktycznie zmieniają stan, mogą sprawdzić poprawność stanu. I lepiej, powinniśmy, ale jeśli nie (powiedzmy w starszych klasach boga)?

Edit:

Chociaż InvalidOperationException wydaje się być najlepiej nadających się przyjętych państw Odpowiedź (a także this one) uwaga:

To jest subtelna, ale semantycznie to ma inne znaczenie niż InvalidOperationException. InvalidOperationException oznacza problem z "protokołem" obiektu, którego osoba wywołująca musi przestrzegać (np. Nie została zainicjowana, zamknięta, ...). W moim przypadku dzwoniący nie zrobił nic złego, jest to obiekt, który jest zepsuty. Chciałbym przetransportować dokładnie tę wiadomość.

Przykład:

switch(this._someType) { 
    case SomeType.A: doSomething(); break; 
    case SomeType.B: doSomethingElse(); break; 
    /*...*/ 
    default: 
    // Unexpected type! Someone introduced a new type and didn't update this. 
    throw new IllegalStateException("Unknown type "+this._someType); 
} 
+3

Ogólnie "InvalidOperationException". –

+0

Proszę zobaczyć mój komentarz do odpowiedzi Matthew Watsonsa na temat 'InvalidOperationException'. –

+2

Lepszym przykładem dla ogólnej zasady może być próba "dodania" elementu do obiektu słownikowego, w którym wewnętrznie połączona lista została uszkodzona (np. Z powodu nieuprawnionego użycia wielowątkowego). Normalnie, 'InvalidOperatonException' wyrzucony z metody' Add' oznaczałby, że element ze wskazanym kluczem został już dodany, a kod, który wychwytuje taki wyjątek, prawdopodobnie oczekiwałby, że jest prawdziwy. Zakładam, że bardzo źle jest rzucić wyjątek typu, który wiąże się z oczekiwaniami, gdy stan obiektu nie pasuje do nich. – supercat

Odpowiedz

35

Należy wyrzucić InvalidOperationException aby wskazać, że obiekt ma nieprawidłowy stan.

Z dokumentacji MSDN (połączone powyżej):

wyjątkiem tego, że jest generowany, gdy połączenie jest nieprawidłowe sposób o stan obiektu.

+8

Może to subtelne, ale semantycznie ma to inne znaczenie. 'InvalidOperationException' wskazuje na problem w" protokole "obiektu, który wywołujący musi przestrzegać (np. Nie został zainicjowany, zamknięty już, ...). W moim przypadku osoba dzwoniąca nie zrobiła nic złego, to obiekt jest * uszkodzony *. Chciałbym przetransportować dokładnie tę wiadomość. –

+3

@IgorLankin W takim przypadku prawdopodobnie będziesz potrzebował 'Trace.Assert (someConditionThatMustBeTrue)' Ponieważ jeśli twój kod jest uszkodzony, nie ma żadnego sensownego wyjątku, który mógłbyś wyrzucić, aby kiedykolwiek miał sens złapać. Byłby to naprawdę wyjątek 'MyCodeIsBroken'! –

+2

(Inna myśl) Nadal powinieneś używać 'InvalidOperationException', ponieważ to właśnie powinieneś użyć do tego w .Net (nawet biorąc pod uwagę twoje rozróżnienie, które w pełni rozumiem) - ale możesz powiedzieć w wiadomości wyjątku, co dokładnie Problem polega na tym, że nie tracisz żadnych informacji. –

1

Najbliższy analog można ustalić jako od Net 2,0 [coś lepiej może być dodane, ponieważ] byłoby ObjectDisposedException, co oznacza, że ​​przedmiot został umieszczony na stałe, nieprawidłowy stan. Taki wyjątek można uznać za "nieoczekiwany", ale to dobrze, ponieważ warunek, który wskazuje, byłby również nieoczekiwany. Ponadto, jeśli metoda na obiekcie wykryje, że jego stan jest nieprawidłowy, powinien po przechwyceniu jak największej ilości informacji o stanie obiektu, które mogą być pomocne przy rozwiązywaniu problemów, celowo umieścić obiekt w stanie trwale nieważnym, tak aby wszystkie przyszłe operacje na nim (poza prośbami o wyodrębnienie informacji, które zostały przechwycone w celu rozwiązywania problemów) rzuci wyjątek.

Z powodu silnego powiązania między IDisposable i ObjectDisposedException, może być lepiej zdefiniować nowy typ wyjątku, który może, ale nie musi dziedziczyć po ObjectDisposedException. Prawdopodobnie, ObjectDisposedException powinno być wyprowadzone z ObjectInvalidatedException, które powinno również mieć CorruptObjectDiscoveredException i CorruptObjectInvalidatedException [poprzednia jest wyrzucana przez pierwszą metodę, która znajduje korupcję, a druga przez kolejne wywołania metody na tym samym obiekcie], ale ja nie jestem na pewno to ma znaczenie.

Najważniejsze jest zapewnienie, że kod, który ma powody przypuszczać, że obiekt może znajdować się w stanie uszkodzonym, wyraźnie unieważnia ten obiekt. Niektórzy sugerują, że metody, które odkrywają nieoczekiwane problemy, powinny próbować obalić cały system. Zdecydowanie nie zgadzam się z tą filozofią. Jeśli metoda umieszcza obiekt w tym, co ma być stanem tymczasowo uszkodzonym, a następnie kończy się przez wyjątek, zanim stan obiektu może zostać naprawiony, powinien całkowicie unieważnić obiekt, zamiast pozostawiać go uszkodzonym. Jeśli po rozwinięciu stosu system nie będzie mógł działać bez teraz unieważnionego obiektu, nastąpi jego zawieszenie w krótkim czasie (lepsza alternatywa niż funkcjonowanie z uszkodzonym stanem). Jeśli jednak proces rozwijania stosu powoduje porzucenie uszkodzonego obiektu (np. Ktoś próbował załadować dokument z pliku niewłaściwego typu, powodując wyjątek w metodzie nazwanej przez LoadDocument), fakt, że obecnie obiekt porzucony jest uszkodzony może być użyteczną informacją dla zrozumienia przyczyny wyjątku, ale może nie mieć żadnych negatywnych konsekwencji dla ogólnego stanu systemu.

+1

Cóż, gdybym zobaczył 'ObjectDisposedException', byłbym bardzo zaskoczony, gdyby nie został zgłoszony, ponieważ operacja została wywołana na usuniętym obiekcie ... –

+0

@MatthewWatson: Tak więc moje zalecenie, że niestandardowy wyjątek może być lepszy. Uważam, że obsługa wyjątków jest (lub powinna) dotyczyć mniej szczegółów dotyczących tego, co się stało, niż wynikającego z tego stanu systemu. Kod, który otrzymuje 'InvalidOperationException' podczas dodawania czegoś do kolekcji słownika-ish, może oczekiwać, że po złapaniu wyjątku kolekcja będzie zawierać element z podanym kluczem. Jeśli to nie jest prawda, metoda nie powinna wyrzucać tego wyjątku. Operacje, które zawodzą z obiektami w nieoczekiwanych stanach, powinny powodować nieoczekiwane wyjątki. – supercat

+0

Rozumiem, ale niestety nieoczekiwane niestandardowe typy wyjątków mogą być dobrym bólem, gdy występują po stronie serwera, a strona klienta nie może ich deserializować. Możesz całkowicie stracić wyjątek i po prostu uzyskać wyjątki związane z deserializacją na kliencie, co bardzo utrudnia ustalenie, co się dzieje (jak się dowiedziałem całkiem niedawno ...;) Jeśli chodzi o przykład słownika - ja don Naprawdę rozumiem, dlaczego uważasz, że kolekcja zawierałaby coś z tym kluczem. Powinieneś dostać "ArgumentException", jeśli tak było. –

Powiązane problemy