2010-07-22 10 views
16

Quale eccezione dovrei usare quando il programma raggiunge uno stato logico che "so" non accadrà, e se lo fa, qualcosa è terribilmente male.Quale eccezione devo lanciare per segnalare un errore interno nel mio programma?

Ad esempio:

int SomeFunction(int arg) { 
    SomeEnum x = Whatever(arg, somePrivateMember); 
    switch (x) { 
     case SomeEnum.Value1: 
      return SomeFunction1(); 
     case SomeEnum.Value1: 
      return SomeFunction2(); 
     default: 
      throw new WhatTypeToThrow(); 
    } 
} 

Chiaramente, ArgumentException è un a lungo girato qui in quanto il valore non valido per x potrebbe provenire da un bug in qualunque(), o una combinazione non valida di argomenti e/o lo stato attuale dell'istanza.

Sto cercando qualcosa come InvalidProgramStateException, InternalErrorException o simile.

Naturalmente potrei definire il mio, ma mi chiedo se ci sia un'eccezione adeguata nel framework.

Modifica: Rimosso il codice di esempio semplice per ridurre la quantità di risposte ArgumentException.

+1

Perché non creare la propria eccezione utilizzando uno dei nomi che hai già suggerito? O che ne dici di un "ShouldNotHappenException"? ;-) –

+2

@ 0xA3 che non è considerata una best practice –

+2

@erik: non si dispone di un errore interno qui. Hai un errore nell'argomento passato al tuo metodo. Questo può essere un errore interno in senso globale, ma quello che hai a livello locale è un 'ArgumentOutOfRangeException', come dice "chibacity" sotto. –

risposta

4

Che dire di InvalidOperationException?

+5

A volte lo uso, ma penso che l'eccezione dica "Non puoi farlo", e quello che voglio dire è "Avresti dovuto essere in grado di farlo, ma c'è un bug". – erikkallen

+0

Da [MSDN] (https://msdn.microsoft.com/en-us/library/system.invalidoperationexception%28v=vs.110%29.aspx): "InvalidOperationException viene utilizzato nei casi in cui non è stato possibile richiamare un metodo è causato da motivi diversi da argomenti non validi. ". Quindi, il mio voto va a questa alternativa. – fernio

+1

@erikkallen, forse la NotImplementedException? – Fred

2

Penso che ArgumentOutOfRangeException sia valido qui ed è quello che uso. È l'argomento dell'istruzione switch che non è gestita poiché è fuori dalla gamma di valori gestiti. Io tendo a codice come questo, in cui il messaggio dice le cose come stanno:

switch (test) 
{ 
    case SomeEnum.Woo: 
     break; 
    case SomeEnum.Yay: 
     break; 
    default: 
    { 
     string msg = string.Format("Value '{0}' for enum '{1}' is not handled.", 
      test, test.GetType().Name); 

     throw new ArgumentOutOfRangeException(msg); 
    } 
} 

Ovviamente il messaggio è ai vostri gusti, ma le basi sono in quello. Aggiungere il valore dell'enum al messaggio è utile non solo per fornire dettagli su ciò che il membro enum conosciuto non è stato gestito, ma anche quando c'è un enum non valido, ovvero il vecchio problema "(666) SomeEnum".

Valore 'OhNoes' per enum 'SomeEnum' non viene gestito.

vs

valore '666' per enum 'SomeEnum' non è gestito.

+2

Cosa succede se il valore modificato non è un argomento? A proposito, ho rimosso il semplice esempio in cui la risposta era probabilmente ArgumentException. – erikkallen

+2

@erikkallen Il valore è un argomento dell'istruzione switch come ho indicato nella mia risposta. –

1

Qui ci sono suggerimenti che mi è stata data:

  • ArgumentException: qualcosa non va con il valore

  • ArgumentNullException: l'argomento è nullo, mentre questo non è consentito

  • ArgumentOutOfRangeException: l'argomento ha un valore esterno all'intervallo valido

In alternativa, derivare la propria classe di eccezione da ArgumentException.

Un ingresso è non valido se non è valido in qualsiasi momento. Mentre un input è inaspettato se non è valido per lo stato corrente del sistema (per il quale InvalidOperationException è una scelta ragionevole in alcune situazioni).

See similar question and answer that I was given.

+1

Il punto della domanda è che lo stato non valido non è correlato agli argomenti. Sono d'accordo, nel caso semplice, ArgumentException può fare, ma non penso che ArgumentException debba essere usato come un generico "oops, non ha funzionato, scommetto che ha a che fare con l'eccezione degli argomenti". – erikkallen

+0

L'istruzione switch è ciò che ha l'argomento fuori intervallo. –

0

"programma raggiunge uno stato logico che io 'so' non accadrà, e se lo fa, c'è qualcosa di terribilmente male."

In questo caso vorrei lanciare un'eccezione Application, accedere a ciò che è possibile e uscire dall'app. Se le cose vanno male, non dovresti cercare di recuperare e/o continuare.

+3

Non penso che sia una buona idea. Lo scopo originale di ApplicationException (prima che fosse deprecato) era che qualsiasi eccezione (prevista) che i lanci delle applicazioni dovrebbero derivare da essa. – erikkallen

1

È consigliabile utilizzare i Contratti di codice non solo per generare eccezioni in questo caso, ma per documentare l'ipotesi errata, magari con un messaggio amichevole per il programmatore. Se sei stato fortunato, la funzione che hai chiamato (Whatever) avrebbe un Contract.Ensures che avrebbe catturato questo errore prima di averlo messo le mani sopra.

4

Perché non l'eccezione InvalidEnumArgumentException? Sembra che sia stato progettato specificamente per questo caso d'uso.

2

Non inserire alcun tipo di eccezione specifico nel codice che si sta guardando. Chiama il numero Trace.Assert, o in questo caso anche Trace.Fail per ottenere un effetto simile a Debug.Assert, eccetto abilitato anche nelle versioni di rilascio (supponendo che le impostazioni non siano cambiate).

Se il listener di traccia predefinito, quello che offre un'interfaccia utente che offre l'eliminazione dell'intero programma o il lancio di un debugger, non è appropriato per le proprie esigenze, impostare un listener di traccia personalizzato in Trace.Listeners che causa un tipo di eccezione privata da lanciare ogni volta che viene chiamato Trace.Fail (anche quando un errore Trace.Assert non riesce).

Il tipo di eccezione deve essere un tipo di eccezione privata poiché, in caso contrario, i chiamanti potrebbero essere tentati di provare a catturare qualsiasi tipo di eccezione che si sta per lanciare. Per questo particolare tipo di eccezione, si vorrà rendere il più chiaro possibile che una versione futura del metodo non genererà più questa particolare eccezione. Non vuoi essere costretto a lanciare un TraceFailedException o qualsiasi altra cosa tu chiami da ora fino all'eternità per preservare la compatibilità con le versioni precedenti.


Un'altra risposta citata Contratti di codice già come alternativa. È, in un modo simile: puoi chiamare Contract.Assert(false). Questo ha lo stesso approccio di renderlo personalizzabile cosa succede se un'asserzione fallisce, ma in questo caso, il comportamento predefinito è di generare un'eccezione, di nuovo di un tipo che non è accessibile esternamente. Tuttavia, per sfruttare al massimo i Contratti di codice, dovresti utilizzare il rewriter statico, che ha sia vantaggi che svantaggi che non entrerò qui. Se per te i professionisti superano i contro, allora usalo con tutti i mezzi. Se preferisci evitare comunque il rewriter statico, ti consiglio di evitare del tutto la classe Contract, dal momento che non è affatto ovvio quali metodi funzionano e non funzionano.

Problemi correlati