Come conservare i messaggi di eccezione

3

In che modo vengono memorizzati i messaggi di eccezione? per qualsiasi dominio. Ci sto pensando da un punto di vista della manutenzione.

if(!Condition1)
    throw new Exception("Some exception");

if(!Condition2)
    throw new Exception("Some exception");

Se è stato deciso di modificare il messaggio di eccezione in quel frammento, dovrebbe essere modificato in due punti; lasciandolo aperto per messaggi incoerenti e simili.

Quanto è meglio memorizzare i messaggi di eccezione allora? Forse come una classe statica con costanti?

public static Exceptions
{
    public const string CONDITION_NOT_MET = "Some exception";
}
...
if(!Condition1)
    throw new Exception(Exceptions.CONDITION_NOT_MET);

if(!Condition2)
    throw new Exception(Exceptions.CONDITION_NOT_MET);

Sono spesso (in produzione) hardcoded?

    
posta Andy Hunt 04.01.2012 - 11:56
fonte

3 risposte

8

Interpreterò ciò che dice @MikeNakis: l'eccezione tipo usata dovrebbe essere abbastanza dettagliata da poter discernere in qualche misura ragionevole il problema dal cercare solo em> a quello ed eventualmente la traccia dello stack. Se l'intento era quello di gettare solo Exception s in giro, allora quel tipo sarebbe stato reso final , sealed o qualunque cosa accada essere il termine nel proprio linguaggio di programmazione di scelta, ma questo non è il caso in qualsiasi lingua o struttura che conosca. In effetti, il rilevamento di Exception è spesso disapprovato, in quanto è un problema che molto probabilmente nasconderà problemi reali e seri.

Il messaggio di eccezione dovrebbe essere usato per fornire dettagli che non possono essere ragionevolmente espressi attraverso il sistema di tipi.

Il tuo secondo esempio è in realtà peggiore, IMO: stai sostituendo tipi di hard-and-fast con stringhe letterali che sono destinate a diventare obsolete, usate male, modificate in modi non previsti in alcune parti del codice, o in qualsiasi numero di altri possibili modi imprecisi. E in un modo che il compilatore non ha un barlume di speranza nell'aiutarti a prendere, in qualsiasi lingua.

I messaggi di eccezione non dovrebbero essere modificati. Nella misura in cui devono essere utilizzati a tutti (che dovrebbe essere moderatamente, IMO, vedere la discussione precedente), dovrebbero essere pensati per i programmatori (e possibilmente utenti esperti, che possono abilitare la visualizzazione dei messaggi attraverso qualche meccanismo), non gli utenti finali. Pertanto, il fraseggio esatto diventa meno importante del fatto che il messaggio descrive chiaramente le condizioni che hanno causato l'eccezione ma che non possono essere adeguatamente espresse attraverso il sistema di tipi.

Inoltre, a meno che tu non abbia davvero bisogno di messaggi di testo in forma libera senza semantica incorporata come chiarificatori di eccezioni (improbabile), sei quasi sempre meglio dimenticare completamente di costruire e trasmettere un singolo messaggio di stringa. Supponiamo che tu abbia un pezzo di codice che richiede che una certa variabile si trovi all'interno di un determinato intervallo e che debba altrimenti generare un'eccezione. Invece di (pseudo-C # /. NET, so che potresti usare le feature per costruire stringhe come StringBuilder o String.Format , ma non è questo il punto qui):

if (x < 3 || x > 10)
    throw new VeryGeneralException("Got " + x.ToString() + " wanted min 3 max 10");

potresti fare qualcosa di simile:

public class OutOfRangeException : Exception
{
    public int Value { get; private set; }
    public int MinValue { get; private set; }
    public int MaxValue { get; private set; }

    public OutOfRangeException(int value, int minvalue, int maxvalue)
    {
        base("Got " + value.ToString() +
             " wanted min " + minvalue.ToString() + " max " + maxvalue.ToString());
        this.Value = value;
        this.MinValue = minvalue;
        this.MaxValue = maxvalue;
    }
}
... then far later ...
if (x < 3 || x > 10)
    throw new OutOfRangeException(value: x, minvalue: 3, maxvalue: 10);

In questo modo:

  • esaminando solo il nome del tipo di eccezione, sai che alcuni valori erano al di fuori dell'intervallo consentito
  • con il messaggio generato risultante, conosci il valore della variabile in questione e il suo intervallo previsto
  • insieme alla traccia dello stack completo, hai un'idea abbastanza buona di come sei arrivato a quel punto (che, a seconda dell'architettura e della semantica del valore in questione, può o non può aiutarti a determinare perché il valore era fuori del suo intervallo consentito)

In questo modo, una singola eccezione, inclusa la traccia dello stack, ti fornisce quanti più dettagli puoi sperare di ottenere una descrizione passo-passo su come ripetere l'errore.

    
risposta data 04.01.2012 - 12:58
fonte
5

A mio parere, il costruttore di Exception non deve accettare un parametro di messaggio stringa né alcun altro tipo di identificatore che rappresenta il messaggio. Il messaggio è il nome del tipo di eccezione .

Nei miei progetti per comodità uso un'eccezione che chiamo GenericException che accetta un messaggio di stringa, ma l'intento è di sostituirlo con un tipo di eccezione specifico, creato appositamente per questo scopo, prima della distribuzione, idealmente prima commit codice sorgente.

Quello che puoi fare è avere un dizionario in cui la chiave è un tipo di eccezione e il valore è il messaggio corrispondente. Puoi anche utilizzare la formattazione nel messaggio e utilizzare reflection per recuperare i valori dei membri dell'eccezione e passarli alla funzione String.Format, in modo da rendere i tuoi messaggi più ricchi.

Quindi, nel tuo caso dovresti definire un ConditionNotMetException , derivato da System.Exception . Se non hai altre informazioni da passarci, lasciatelo come una classe vuota. In alternativa, potresti voler includere alcuni membri, contenenti informazioni aggiuntive sulla condizione che non è stata soddisfatta, perché non è stata soddisfatta, ecc.

Tuttavia, questi membri dovrebbero essere solo valori non elaborati, non dovrebbero essere elaborati in messaggi stringa dall'eccezione. Ad esempio, se hai un'eccezione chiamata DateOutOfRangeException potresti voler includere in essa campi 3 DateTime : uno per la data che risulta essere fuori intervallo e altri due per definire l'intervallo. Quindi, è responsabilità dell'applicazione presentare all'utente un messaggio significativo contenente queste tre date.

    
risposta data 04.01.2012 - 12:20
fonte
4

Lascia che il messaggio sia chiaro. Una buona cosa da dire è cosa è andato storto:

if(!Condition1) throw new Exception("!Condition1");

if(!Condition2) throw new Exception("!Condition2");

Più l'espressione è complessa in if più informazioni avrai bisogno per evitare un passo di debug. Ad esempio

if ((x>10) || (y<0)) throw new RuntimeException("(x>10) || (y<0), x="+x+",y="+y);

Ciò consentirà al tecnico di manutenzione di analizzare l'errore senza dover eseguire nuovamente il programma. Un giorno lo apprezzerai

    
risposta data 04.01.2012 - 13:22
fonte

Leggi altre domande sui tag