2013-05-05 17 views
30

Ho sempre perso un tipo di eccezione built-in in C# che indica che un oggetto è danneggiato. Cosa butti in questi casi?Quale eccezione lanciare sullo stato dell'oggetto non valido?

Di solito mi manca quando mi rendo conto che un metodo, che dovrebbe funzionare su un oggetto, fallirebbe se l'oggetto avesse un certo stato. In tali situazioni, spesso sospetto che questo stato probabilmente non sarà mai raggiunto. Ma essendo difensivo a riguardo, vorrei lanciare un'eccezione nel caso in cui lo fosse (ad esempio dopo un futuro cambio di codice).

Per gli argomenti del metodo abbiamo ArgumentException in modo da poter negare i parametri non validi. Ma per stato dell'oggetto? In Java userei IllegalStateException.

Ovviamente si potrebbe obiettare che i metodi, che in realtà cambiano lo stato, potrebbero verificare la correttezza dello stato. E dovrebbero farlo meglio, ma poi se non lo fanno (diciamo nelle lezioni di Dio in eredità)?

Edit:

Anche se InvalidOperationException sembra essere la soluzione migliore, come gli stati accettati risposta (e anche this one), si prega di notare:

E 'sottile, ma semanticamente questo ha un significato diverso di InvalidOperationException. InvalidOperationException indica un problema nel "protocollo" dell'oggetto, a cui il chiamante deve obbedire (ad es. Non inizializzato, chiuso già, ...). Nel mio caso il chiamante non ha fatto nulla di sbagliato, è l'oggetto che è rotto. Vorrei trasportare esattamente quel messaggio.

Esempio:

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

Generalmente, 'InvalidOperationException'. –

+0

Si prega di vedere il mio commento a Matthew Watsons risposta a 'InvalidOperationException'. –

+2

Un esempio migliore per il principio generale potrebbe essere quello di cercare di aggiungere un elemento ad un oggetto dizionario-ish in cui un elenco collegato interno è corrotto (ad esempio a causa di un uso multi-thread illegittimo). Normalmente, una 'InvalidOperatonException' generata da un metodo' Add' indica che un elemento con la chiave indicata è già stato aggiunto e il codice che cattura tale eccezione probabilmente si aspetta che sia vero. Direi che è pessimo gettare un'eccezione di un tipo che ha associato aspettative quando lo stato di un oggetto non le soddisfa. – supercat

risposta

35

Si dovrebbe gettare InvalidOperationException per indicare che un oggetto ha stato non valido.

Dalla documentazione MSDN (linkato sopra):

L'eccezione generata quando una chiamata al metodo è valido per lo stato corrente dell'oggetto.

+8

Forse è sottile, ma semanticamente questo ha un significato diverso. 'InvalidOperationException' indica un problema nel" protocollo "dell'oggetto, a cui il chiamante deve obbedire (ad es. Non inizializzato, chiuso già, ...). Nel mio caso il chiamante non ha fatto nulla di sbagliato, è l'oggetto che è * rotto *. Vorrei trasportare esattamente quel messaggio. –

+3

@IgorLankin In tal caso, probabilmente vorrai 'Trace.Assert (someConditionThatMustBeTrue)' Perché se il tuo codice è rotto, non c'è un'eccezione ragionevole che potresti lanciare che avrebbe mai avuto senso catturare. Sarebbe effettivamente un'eccezione 'MyCodeIsBroken'! –

+2

(Un altro pensiero) Si dovrebbe ancora usare 'InvalidOperationException', poiché è ciò che si suppone di usare per questo in .Net (anche dato la tua distinzione, che capisco perfettamente) - ma puoi dire nel messaggio di eccezione esattamente ciò che il il problema è che non perdi nessuna informazione –

1

L'analogo più vicino che riesco a capire come di .Net 2.0 [qualcosa di meglio potrebbe essere stato aggiunto in quanto] sarebbe ObjectDisposedException, il che indica che un oggetto è stato collocato in uno stato permanentemente invalido. Tale eccezione può essere considerata "inaspettata", ma questa è una buona cosa, poiché la condizione che sta indicando sarebbe allo stesso modo inaspettata. Inoltre, se un metodo su un oggetto scopre che il suo stato non è valido, dopo aver acquisito tutte le informazioni sullo stato dell'oggetto che potrebbero essere utili per la risoluzione dei problemi, posizionare deliberatamente l'oggetto in uno stato permanente non valido in modo che tutte le operazioni future su di esso (a parte forse le richieste di estrarre le informazioni catturate per scopi di risoluzione dei problemi) genererà un'eccezione.

A causa della forte associazione tra IDisposable e ObjectDisposedException, potrebbe essere preferibile definire un nuovo tipo di eccezione che può ereditare o meno da ObjectDisposedException. Probabilmente, ObjectDisposedException avrebbe dovuto essere derivato da un ObjectInvalidatedException, che dovrebbe anche avere CorruptObjectDiscoveredException e CorruptObjectInvalidatedException [il primo è stato lanciato dal primo metodo che trova il danneggiamento, e il secondo da chiamate di metodo successive sullo stesso oggetto], ma io non sono certo che conta davvero.

Ciò che è più importante penso è di garantire che il codice che ha motivo di ritenere che un oggetto possa essere in uno stato corrotto invalida espressamente l'oggetto. Alcune persone hanno suggerito che i metodi che scoprono problemi imprevisti dovrebbero cercare di far cadere l'intero sistema. Sono fortemente in disaccordo con quella filosofia. Se un metodo mette un oggetto in quello che dovrebbe essere uno stato temporaneamente danneggiato e quindi esce da un'eccezione prima che lo stato dell'oggetto possa essere corretto, dovrebbe invalidare completamente l'oggetto piuttosto che lasciarlo danneggiato. Se dopo lo sbobinamento dello svolgimento il sistema non può funzionare senza l'oggetto ora invalidato, arriverà in modo anomalo in breve tempo (un'alternativa migliore rispetto al funzionamento con stato corrotto). Se, tuttavia, il processo di srotolamento dello stack provoca l'abbandono dell'oggetto corrotto (ad es. Qualcuno ha provato a caricare un documento da un file di tipo errato, causando un'eccezione all'interno di un metodo chiamato da LoadDocument), il fatto che l'ora- L'oggetto abbandonato era corrotto possono essere informazioni utili per capire perché è stata lanciata un'eccezione, ma non può avere implicazioni avverse per la salute generale del sistema.

+1

Beh, se vedessi un 'ObjectDisposedException' sarei molto sorpreso se non fosse stato lanciato perché un'operazione è stata chiamata su un oggetto disposto ... –

+0

@MatthewWatson: Quindi la mia raccomandazione che un'eccezione personalizzata potrebbe essere migliore. Ritengo che la gestione delle eccezioni sia (o dovrebbe essere) meno preoccupante per i dettagli di ciò che è accaduto rispetto allo stato del sistema risultante. Codice che ottiene un 'InvalidOperationException' quando si aggiunge qualcosa ad una raccolta di dizionario-ish potrebbe aspettarsi che quando viene rilevata l'eccezione, la collezione conterrà un elemento con la chiave data. Se ciò non è vero, il metodo non dovrebbe generare quell'eccezione. Le operazioni che falliscono con oggetti in stati imprevisti dovrebbero causare eccezioni impreviste. – supercat

+0

Capisco, ma sfortunatamente i tipi di eccezioni personalizzate inaspettate possono essere un problema giusto quando si verificano sul lato server e il lato client non può deserializzarlo. Si può finire per perdere totalmente l'eccezione e ottenere solo eccezioni relative alla deserializzazione sul client, il che rende davvero difficile capire cosa sta succedendo (come ho scoperto abbastanza recentemente ...;) Per quanto riguarda l'esempio del dizionario - I don capisco davvero perché penseresti che la collezione conterrebbe qualcosa con quella chiave. Dovresti ottenere un 'ArgumentException' se fosse il caso. –

Problemi correlati