2013-05-05 10 views
30

Ich verpasste immer einen eingebauten Ausnahme-Typ in C#, der anzeigen würde, dass ein Objekt beschädigt ist. Was werfen Sie in solchen Fällen?Welche Ausnahme wird auf ungültigen Objektstatus geworfen?

Normalerweise vermisse ich es, wenn ich feststelle, dass eine Methode, die an einem Objekt arbeiten soll, fehlschlagen würde, wenn das Objekt einen bestimmten Zustand hätte. In solchen Situationen vermute ich oft, dass dieser Zustand wahrscheinlich nie erreicht wird. Aber wenn ich mich in der Defensive befinde, würde ich gerne eine Ausnahme auslösen, falls dies der Fall sein sollte (z. B. nach einem zukünftigen Codewechsel).

Für Methodenargumente haben wir ArgumentException, so dass wir ungültige Parameter verweigern können. Aber für den Objektstatus? In Java würde ich IllegalStateException verwenden.

Natürlich könnte man argumentieren, dass die Methoden, die den Zustand tatsächlich ändern, auf die Korrektheit des Zustandes prüfen könnten. Und sie sollten besser, aber dann, wenn sie es nicht tun (sagen wir in alten Gottheiten)?

Edit:

Obwohl InvalidOperationException scheint die beste Lösung zu sein, wie die akzeptierte Antwort Staaten (und auch this one), bitte beachten Sie:

Es ist subtil, aber semantisch hat dies eine andere Bedeutung als InvalidOperationException. InvalidOperationException zeigt ein Problem im "Protokoll" des Objekts an, das der Aufrufer befolgen muss (z. B. nicht initialisiert, bereits geschlossen, ...). In meinem Fall hat der Anrufer nichts falsch gemacht, es ist das Objekt, das kaputt ist. Ich möchte genau diese Nachricht transportieren.

Beispiel:

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

Im Allgemeinen "InvalidOperationException". –

+0

Bitte beachten Sie meinen Kommentar zu Matthew Watsons Antwort über 'InvalidOperationException'. –

+2

Ein besseres Beispiel für das allgemeine Prinzip könnte sein, zu versuchen, ein Objekt zu einem Wörterbuch-Objekt hinzuzufügen, in dem eine interne verknüpfte Liste beschädigt wurde (z.B. aufgrund illegitimer Multithread-Verwendung). Normalerweise würde eine 'InvalidOperatonException', die von einer' Add'-Methode ausgelöst wird, anzeigen, dass ein Element mit dem angegebenen Schlüssel bereits hinzugefügt wurde, und Code, der eine solche Ausnahme abfängt, würde wahrscheinlich erwarten, dass dies wahr ist. Ich würde postulieren, dass es sehr schlecht ist, eine Ausnahme eines Typs zu werfen, der Erwartungen hat, wenn der Zustand eines Objekts nicht zu ihnen passt. – supercat

Antwort

35

Sie sollten InvalidOperationException, um anzuzeigen, zu werfen, dass ein Objekt ungültigen Zustand hat.

Aus der MSDN-Dokumentation (oben verlinkten):

Die Ausnahme, die ausgelöst wird, wenn ein Methodenaufruf für den aktuellen Zustand des Objekts ungültig ist.

+8

Vielleicht ist es subtil, aber semantisch hat das eine andere Bedeutung. "InvalidOperationException" zeigt ein Problem im "Protokoll" des Objekts an, das der Aufrufer zu befolgen hat (z. B. nicht initialisiert, bereits geschlossen, ...). In meinem Fall hat der Anrufer nichts falsch gemacht, es ist das Objekt, das * kaputt * ist. Ich möchte genau diese Nachricht transportieren. –

+3

@IgorLankin In diesem Fall würden Sie wahrscheinlich 'Trace.Assert (someConditionThatMustBeTrue)' 'Wenn Ihr Code kaputt ist, gibt es keine vernünftige Ausnahme, die Sie werfen könnten, dass es jemals sinnvoll wäre, zu fangen. Es wäre effektiv eine 'MyCodesIsBroken' Ausnahme! –

+2

(Noch ein Gedanke) Sie sollten immer noch 'InvalidOperationException' verwenden, da Sie dies in .Net (auch bei Ihrer Unterscheidung, die ich vollständig verstehe) verwenden sollen - aber Sie können in der Ausnahmebedingungsnachricht genau sagen, was Problem ist, so verlieren Sie keine Informationen. –

1

Das nächste Analogon I als von .Net 2.0 Abbildung kann [etwas besser kann hinzugefügt wurden seit] ObjectDisposedException sein würde, was darauf hindeutet, dass ein Objekt hat sich zu einem permanent ungültigen Zustand gelegt. Solch eine Ausnahme kann als "unerwartet" betrachtet werden, aber das ist eine gute Sache, da die Bedingung, die sie anzeigt, ebenfalls unerwartet wäre. Wenn eine Methode für ein Objekt entdeckt, dass ihr Status ungültig ist, sollte sie nach dem Erfassen von so vielen Informationen über den Status des Objekts, die für die Fehlersuche hilfreich sein könnten, das Objekt absichtlich in einen permanent ungültigen Zustand versetzen darauf (anders als vielleicht Anfragen, die Informationen zu extrahieren, die für die Fehlersuche erfasst wurden) wird eine Ausnahme ausgelöst.

Aufgrund der starken Assoziation zwischen IDisposable und ObjectDisposedException ist es möglicherweise besser, einen neuen Ausnahmetyp zu definieren, der von ObjectDisposedException erben kann oder nicht. Wohl sollte ObjectDisposedException von einer ObjectInvalidatedException abgeleitet sein, die auch CorruptObjectDiscoveredException und CorruptObjectInvalidatedException [ersteres wird von der ersten Methode, die die Korruption findet, und letztere durch nachfolgende Methodenaufrufe auf das gleiche Objekt geworfen] haben, aber ich bin nicht sicher, dass es wirklich zählt.

Was am wichtigsten ist, denke ich, ist sicherzustellen, dass Code, der Grund zu der Annahme hat, dass ein Objekt in einem beschädigten Zustand sein kann, das Objekt ausdrücklich ungültig macht. Einige Leute haben vorgeschlagen, dass Methoden, die unerwartete Probleme entdecken, versuchen sollten, das ganze System zu Fall zu bringen. Ich stimme dieser Philosophie nicht zu. Wenn eine Methode ein Objekt in einen temporär beschädigten Zustand versetzt und dann über eine Ausnahme beendet wird, bevor der Status des Objekts behoben werden kann, sollte das Objekt vollständig ungültig gemacht werden, anstatt es beschädigt zu lassen. Wenn nach dem Abwickeln des Stapels das System nicht ohne das jetzt invalidierte Objekt funktionieren kann, wird es in kurzer Zeit abstürzen (eine bessere Alternative als das Funktionieren mit einem beschädigten Zustand). Wenn der Prozess des Abwickelns des Stapels jedoch dazu führt, dass das beschädigte Objekt aufgegeben wird (z. B. wenn jemand versucht hat, ein Dokument aus einer Datei des falschen Typs zu laden, verursacht eine Ausnahme innerhalb einer von LoadDocument aufgerufenen Methode), Das abgebrochene Objekt war korrupt und kann nützlich sein, um zu verstehen, warum eine Ausnahme ausgelöst wurde. Es kann jedoch keine nachteiligen Auswirkungen auf den allgemeinen Zustand des Systems haben.

+1

Nun, wenn ich eine 'ObjectDisposedException' sah, wäre ich sehr überrascht, wenn sie nicht ausgelöst wurde, weil eine Operation für ein disponiertes Objekt aufgerufen wurde ... –

+0

@MatthewWatson: Also meine Empfehlung, dass eine benutzerdefinierte Ausnahme besser sein könnte. Ich bin der Ansicht, dass die Ausnahmebehandlung weniger mit den Einzelheiten des Geschehenen als mit dem resultierenden Systemstatus zu tun hat (oder sein sollte). Code, der eine 'InvalidOperationException' abruft, wenn er einer dictionary-ish-Auflistung etwas hinzufügt, kann erwarten, dass die Sammlung beim Auffangen der Ausnahme ein Element mit dem angegebenen Schlüssel enthält. Wenn das nicht der Fall ist, sollte die Methode diese Ausnahme nicht auslösen. Operationen, die mit Objekten in unerwarteten Status fehlschlagen, sollten unerwartete Ausnahmen verursachen. – supercat

+0

Ich verstehe, aber leider unerwartete benutzerdefinierte Ausnahme-Typen können ein richtiger Schmerz sein, wenn sie Server-Seite auftreten und die Client-Seite kann es nicht deserialisieren. Sie können am Ende die Ausnahme komplett verlieren und nur Deserialisierungs-bezogene Ausnahmen auf dem Client bekommen, was es wirklich schwierig macht herauszufinden, was vor sich geht (wie ich es vor kurzem herausgefunden habe ...;) Zum Wörterbuch Beispiel - ich weiß nicht verstehe nicht wirklich, warum du denkst, dass die Sammlung etwas mit diesem Schlüssel enthalten würde. Sie sollten eine "ArgumentException" erhalten, wenn dies der Fall war. –

Verwandte Themen