Come utilizzare try catch per la gestione delle eccezioni è la migliore pratica


201

pur mantenendo il codice del mio collega anche da qualcuno che afferma di essere uno sviluppatore senior, vedo spesso il seguente codice:

try
{
  //do something
}
catch
{
  //Do nothing
}

o a volte scrivono informazioni di registrazione per registrare file come il seguente try catchblocco

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

Mi chiedo solo se ciò che hanno fatto è la migliore pratica? Mi rende confuso perché nel mio pensiero gli utenti dovrebbero sapere cosa succede con il sistema.

Per favore, dammi qualche consiglio.


128
Lo snippet n. 1 è il 99,999% delle volte inaccettabile.
leppie,

22
La visualizzazione dell'eccezione direttamente all'utente non è mai una buona idea principalmente per due motivi: 1. se si tratta di utenti abituali, sarà infastidito dalla lettura del messaggio di errore che dice molto poco per lui / lei. 2. se è un cosiddetto hacker, può ottenere informazioni utili. La best practice, IMO, è registrare l'eccezione e mostrare un messaggio di errore amichevole.
Leri,

4
@leppie Se si verifica qualcosa di inaspettato (come NullReferenceo ArgumentNullche non fa parte del flusso dell'applicazione) significa che c'è un bug che deve essere risolto, quindi registrarli aiuterà a eseguire il debug del codice molto più velocemente.
Leri,

14
L'uso di un blocco try-catch per nascondere un'eccezione è generalmente il risultato di una programmazione pigra. È una scorciatoia che viene spesso utilizzata invece di scrivere il codice di convalida per testare gli input. Molto occasionalmente ci sono momenti in cui può verificarsi un'eccezione che non influisce sul funzionamento del codice e nasconderlo in questo modo potrebbe essere OK. Questo è abbastanza raro tuttavia.
Corey,

12
@Toan, beh, se si tratta di un lavoro batch, sto rilevando il livello più alto (principale) per accedere, quindi ricomincio per innescare un allarme che il lavoro è terminato in modo anomalo. Se si tratta di un'app Web, sto lasciando il fumetto dell'eccezione a un gestore globale, registrando e quindi reindirizzando l'utente a una schermata di errore. Lo scenario del tuo caso d'uso determina ciò che fai con quell'eccezione dopo averlo registrato o altrimenti gestito.
Anthony Pegram,

Risposte:


300

La mia strategia di gestione delle eccezioni è:

  • Per catturare tutte le eccezioni non gestite collegandosi a Application.ThreadException event, quindi decidere:

    • Per un'applicazione UI: per visualizzarla all'utente con un messaggio di scuse (winforms)
    • Per un servizio o un'applicazione console: accedi a un file (servizio o console)

Quindi allego sempre ogni parte di codice che viene eseguita esternamente in try/catch:

  • Tutti gli eventi generati dall'infrastruttura Winforms (Load, Click, SelectedChanged ...)
  • Tutti gli eventi generati da componenti di terze parti

Quindi allego in "prova / cattura"

  • Tutte le operazioni che conosco potrebbero non funzionare sempre (operazioni IO, calcoli con una potenziale divisione zero ...). In tal caso, ne lancio uno nuovo ApplicationException("custom message", innerException)per tenere traccia di ciò che è realmente accaduto

Inoltre, faccio del mio meglio per ordinare correttamente le eccezioni . Ci sono eccezioni che:

  • deve essere mostrato all'utente immediatamente
  • richiede un po 'di elaborazione extra per mettere insieme le cose quando accadono per evitare problemi a cascata (es: mettere .EndUpdate nella finallysezione durante un TreeViewriempimento)
  • all'utente non importa, ma è importante sapere cosa è successo. Quindi li registro sempre:

    • Nel registro eventi
    • o in un file .log sul disco

È buona norma progettare alcuni metodi statici per gestire le eccezioni nei gestori degli errori di livello superiore dell'applicazione.

Mi sforzo anche di provare a:

  • Ricorda che TUTTE le eccezioni sono gorgogliate al livello superiore . Non è necessario inserire gestori di eccezioni ovunque.
  • Non è necessario che le funzioni riutilizzabili o chiamate in profondità visualizzino o registrino le eccezioni: vengono fatte gorgogliare automaticamente o ricodificate con alcuni messaggi personalizzati nei gestori delle mie eccezioni.

Quindi finalmente:

Male:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Inutili:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Provare finalmente senza una cattura è perfettamente valido:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Cosa faccio al massimo livello:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Cosa faccio in alcune funzioni chiamate:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

C'è molto a che fare con la gestione delle eccezioni (eccezioni personalizzate) ma quelle regole che cerco di tenere a mente sono sufficienti per le semplici applicazioni che faccio.

Ecco un esempio di metodi di estensione per gestire le eccezioni rilevate in modo comodo. Sono implementati in modo da poter essere concatenati ed è molto semplice aggiungere la propria elaborazione delle eccezioni rilevate.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}

98
catch(Exception ex) { throw ex; }in C # è peggio che ridondante (indipendentemente dal tipo di eccezione che si sta rilevando). Per ricodificare, utilizzare throw;. Con il primo, l'eccezione sembrerà provenire dal tuo throw exmentre con il secondo, avrà origine correttamente dalla throwdichiarazione originale .
un CVn del

2
Perché agganciare l' Application.ThreadExceptionevento e racchiudere ogni eccezione con a catch(Exception ex) {ex.Log(ex);}. Probabilmente sarei d'accordo sul fatto che il primo è una pratica eccellente, ma il secondo aggiunge il rischio di duplicare i log degli errori e nasconde che si è verificata l'eccezione. Inoltre throw exè molto, molto male.
Keith,

1
Ho capito di catch (Exception ex) {throw ex; } essere inutili. Quindi suppongo che "ridondante" non sia la parola migliore per dire "Non farlo". Ecco perché ho cambiato un po 'il post per affermare meglio che i due primi esempi di try catch devono essere evitati.
Larry,

3
Risposta grandiosa e costruttiva, soprattutto mi è piaciuta la frase Solo aria :) E grazie per l' Application.ThreadExceptionevento, non ne ero a conoscenza, molto utile.
Mahdi Tahsildari


61

La migliore pratica è che la gestione delle eccezioni non dovrebbe mai nascondere i problemi . Ciò significa che i try-catchblocchi dovrebbero essere estremamente rari.

Ci sono 3 circostanze in cui l'uso di ha un try-catchsenso.

  1. Gestisci sempre le eccezioni note il più in basso possibile. Tuttavia, se ti aspetti un'eccezione, di solito è meglio provare prima. Ad esempio l'analisi, la formattazione e le eccezioni aritmetiche sono quasi sempre meglio gestite prima dai controlli logici, piuttosto che da uno specifico try-catch.

  2. Se è necessario eseguire un'operazione su un'eccezione (ad esempio la registrazione o il rollback di una transazione), ripetere l'eccezione.

  3. Gestisci sempre le eccezioni sconosciute il più in alto possibile: l' unico codice che dovrebbe consumare un'eccezione e non rilanciarla dovrebbe essere l'interfaccia utente o l'API pubblica.

Supponiamo che ti stia connettendo a un'API remota, qui sai che ti aspetti alcuni errori (e ci sono cose in quelle circostanze), quindi questo è il caso 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Si noti che non vengono rilevate altre eccezioni, poiché non sono previste.

Supponiamo ora che stai provando a salvare qualcosa nel database. Dobbiamo ripristinarlo se fallisce, quindi abbiamo il caso 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Nota che lanciamo nuovamente l'eccezione: il codice più in alto deve ancora sapere che qualcosa è fallito.

Finalmente abbiamo l'interfaccia utente: qui non vogliamo avere eccezioni completamente non gestite, ma non vogliamo nemmeno nasconderle. Ecco un esempio del caso 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Tuttavia, la maggior parte dei framework API o UI ha metodi generici per eseguire il caso 3. Ad esempio ASP.Net ha una schermata di errore gialla che scarica i dettagli dell'eccezione, ma che può essere sostituita con un messaggio più generico nell'ambiente di produzione. Seguire queste è la migliore pratica perché ti fa risparmiare molto codice, ma anche perché la registrazione e la visualizzazione degli errori dovrebbero essere decisioni di configurazione piuttosto che hard-coded.

Tutto ciò significa che il caso 1 (eccezioni note) e il caso 3 (gestione dell'interfaccia utente una tantum) hanno entrambi modelli migliori (evitare l'errore previsto o la gestione dell'errore manuale all'interfaccia utente).

Anche il caso 2 può essere sostituito da schemi migliori, ad esempio gli ambiti di transazione (using blocchi che eseguono il rollback di qualsiasi transazione non impegnata durante il blocco) rendono più difficile per gli sviluppatori sbagliare il modello di best practice.

Ad esempio supponiamo di avere un'applicazione ASP.Net su larga scala. La registrazione degli errori può avvenire tramite ELMAH , la visualizzazione degli errori può essere un messaggio informativo locale e un bel messaggio localizzato in produzione. Le connessioni al database possono essere tutte tramite ambiti e usingblocchi di transazione . Non hai bisogno di un singolo try-catchblocco.

TL; DR: la migliore pratica è di non usare affatto i try-catchblocchi.


4
@Jorj dovresti leggere l'intero post, e se non sei ancora d'accordo forse sarebbe più costruttivo contrastare uno dei miei argomenti di supporto piuttosto che affermare che non ti piace la mia conclusione. C'è quasi sempre uno schema migliore di try-catch- può (molto occasionalmente) essere utile e non sto sostenendo che non dovresti mai usarli, ma il 99% delle volte c'è un modo migliore.
Keith,

La migliore risposta di gran lunga: quasi ogni tipo di sviluppo .net ha un HANDLER di qualche tipo che è molto più adatto a gestire le eccezioni a livello globale, rendendo molto più facile gestirle in modo coerente e rendendo molto più semplice lasciarlo semplicemente soffiare in fase di sviluppo (perché qualcuno dovrebbe voler scavare attraverso un file di registro per una traccia dello stack ??) @Kieth, vorrei condurre con il tuo TLDR e aggiungere alcuni esempi di gestori globali (ad esempio ThreadException, Application_Error, ecc.). Cattura sicuramente errori SPECIFICI, ma è folle racchiudere il metodo ever in un tentativo / catch / log
b_levitt

34

Un'eccezione è un errore di blocco .

Prima di tutto, la migliore pratica dovrebbe essere non gettare eccezioni per qualsiasi tipo di errore, a meno che non sia un errore di blocco .

Se l'errore sta bloccando , quindi genera l'eccezione. Una volta che l'eccezione è già stata lanciata, non è necessario nasconderla perché è eccezionale; informa l'utente a riguardo (dovresti riformattare l'intera eccezione a qualcosa di utile per l'utente nell'interfaccia utente).

Il tuo compito come sviluppatore di software è di cercare di prevenire un caso eccezionale in cui alcuni parametri o situazioni di runtime potrebbero finire in un'eccezione. Cioè, le eccezioni non devono essere disattivate, ma devono essere evitate .

Ad esempio, se sai che alcuni input interi potrebbero avere un formato non valido, usa int.TryParseinvece di int.Parse. Ci sono molti casi in cui puoi farlo invece di dire semplicemente "se fallisce, lancia semplicemente un'eccezione".

Generare eccezioni è costoso.

Se, dopo tutto, viene generata un'eccezione, invece di scrivere l'eccezione nel registro una volta che è stata generata, una delle migliori pratiche è catturarla in un gestore di eccezioni alla prima possibilità . Per esempio:

  • ASP.NET: Global.asax Application_Error
  • Altri: evento AppDomain.FirstChanceException .

La mia posizione è che i tentativi / catture locali siano più adatti per la gestione di casi speciali in cui è possibile tradurre un'eccezione in un'altra o quando si desidera "disattivarla" per un caso molto, molto, molto, molto speciale (un bug di libreria generare un'eccezione non correlata che è necessario disattivare l'audio per risolvere l'intero bug).

Per il resto dei casi:

  • Cerca di evitare le eccezioni.
  • Se ciò non è possibile: gestori di eccezioni alla prima possibilità.
  • Oppure usa un aspetto PostSharp (AOP).

Risposta a @thewhiteambit su alcuni commenti ...

@thewhiteambit ha detto:

Le eccezioni non sono errori fatali, sono eccezioni! A volte non sono nemmeno errori, ma considerarli errori fatali è completamente falsa comprensione di cosa siano le eccezioni.

Prima di tutto, come un'eccezione non può essere nemmeno un errore?

  • Nessuna connessione al database => eccezione.
  • Formato stringa non valido per l'analisi di un'eccezione type =>
  • Cercando di analizzare JSON e mentre l'input non è in realtà un'eccezione JSON =>
  • Argomento nullmentre l'oggetto era previsto => eccezione
  • Alcune librerie hanno un bug => genera un'eccezione imprevista
  • C'è una connessione socket e viene disconnesso. Quindi si tenta di inviare un messaggio => eccezione
  • ...

Potremmo elencare 1k casi in cui viene generata un'eccezione e, dopo tutto, uno qualsiasi dei possibili casi sarà un errore .

Un'eccezione è un errore, perché alla fine è un oggetto che raccoglie informazioni diagnostiche: ha un messaggio e succede quando qualcosa va storto.

Nessuno lancerebbe un'eccezione quando non esiste un caso eccezionale. Le eccezioni dovrebbero bloccare gli errori perché, una volta che vengono lanciate, se non si tenta di cadere nell'uso, provare / catturare e le eccezioni per implementare il flusso di controllo significano che l'applicazione / servizio interromperà l'operazione che è entrata in un caso eccezionale .

Inoltre, consiglio a tutti di verificare il paradigma fail-fast pubblicato da Martin Fowler (e scritto da Jim Shore) . È così che ho sempre capito come gestire le eccezioni, anche prima di arrivare a questo documento qualche tempo fa.

[...] considerali errori fatali è una comprensione completamente falsa di quali siano le eccezioni.

Di solito le eccezioni interrompono il flusso di operazioni e vengono gestite per convertirle in errori comprensibili all'uomo. Pertanto, sembra che un'eccezione sia in realtà un paradigma migliore per gestire i casi di errore e lavorarci su per evitare un crash completo dell'applicazione / servizio e informare l'utente / consumatore che qualcosa è andato storto.

Altre risposte alle preoccupazioni di @thewhiteambit

Ad esempio, in caso di mancata connessione al database, il programma potrebbe eccezionalmente continuare con la scrittura su un file locale e inviare le modifiche al database una volta che sarà nuovamente disponibile. Il tuo casting String-To-Number non valido potrebbe essere tentato di analizzare nuovamente con l'interpretazione lingua-locale su Exception, come quando si tenta che la lingua inglese predefinita su Parse ("1,5") non riesca e si riprovi con l'interpretazione tedesca che è completamente bene perché usiamo la virgola anziché il punto come separatore. Vedi queste eccezioni non devono nemmeno essere bloccate, hanno solo bisogno di una gestione delle eccezioni.

  1. Se la tua app potrebbe funzionare offline senza conservare i dati nel database, non dovresti usare eccezioni , poiché l'implementazione del flusso di controllo tramite try/catchè considerata un anti-pattern. Il lavoro offline è un possibile caso d'uso, quindi si implementa il flusso di controllo per verificare se il database è accessibile o meno, non si attende fino a quando non è raggiungibile .

  2. L' analisi è anche un caso previsto ( non CASO ECCEZIONALE ). Se ti aspetti questo, non usi eccezioni per controllare il flusso! . Ottieni alcuni metadati dall'utente per sapere qual è la sua cultura e usi i formattatori per questo! .NET supporta anche questo e altri ambienti, e un'eccezione perché la formattazione dei numeri deve essere evitata se si prevede un uso specifico della cultura dell'applicazione / servizio .

Un'eccezione non gestita di solito diventa un errore, ma le eccezioni in sé non sono codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Questo articolo è solo un'opinione o un punto di vista dell'autore.

Dal momento che Wikipedia può anche essere solo l'opinione degli autori articolari, non direi che è il dogma , ma controlla cosa dice Coding per articolo di eccezione da qualche parte in alcuni paragrafi:

[...] L'uso di queste eccezioni per gestire errori specifici che si presentano per continuare il programma si chiama codifica per eccezione. Questo anti-pattern può degradare rapidamente il software in termini di prestazioni e manutenibilità.

Dice anche da qualche parte:

Utilizzo dell'eccezione errato

Spesso la codifica per eccezione può comportare ulteriori problemi nel software con un utilizzo errato dell'eccezione. Oltre a utilizzare la gestione delle eccezioni per un problema univoco, l'utilizzo errato delle eccezioni lo porta ulteriormente eseguendo il codice anche dopo che viene sollevata l'eccezione. Questo scarso metodo di programmazione ricorda il metodo goto in molti linguaggi software ma si verifica solo dopo che è stato rilevato un problema nel software.

Onestamente, credo che il software non possa essere sviluppato non prendendo sul serio i casi d'uso. Se lo sai che ...

  • Il tuo database può andare offline ...
  • Alcuni file possono essere bloccati ...
  • Alcune formattazioni potrebbero non essere supportate ...
  • La convalida di alcuni domini potrebbe non riuscire ...
  • L'app dovrebbe funzionare in modalità offline ...
  • qualunque sia il caso d'uso ...

... non userete eccezioni per quello . Si potrebbe sostenere questi casi d'uso utilizzando flusso di controllo regolare.

E se alcuni casi d'uso imprevisti non sono coperti, il tuo codice fallirà rapidamente, perché genererà un'eccezione . Giusto, perché un'eccezione è un caso eccezionale .

In altra parte, e, infine, a volte si copre casi eccezionali gettando le eccezioni previste , ma non gettare loro di implementare il flusso di controllo. Lo fai perché vuoi notificare ai livelli superiori che non supporti alcuni casi d'uso o che il tuo codice non funziona con alcuni argomenti o dati / proprietà dell'ambiente.


6

L'unica volta che dovresti preoccupare i tuoi utenti di qualcosa che è accaduto nel codice è se c'è qualcosa che possono o devono fare per evitare il problema. Se possono modificare i dati in un modulo, premere un pulsante o modificare un'impostazione dell'applicazione per evitare il problema, quindi informarli. Ma avvisi o errori che l'utente non ha la possibilità di evitare fa perdere loro la fiducia nel prodotto.

Eccezioni e registri sono per te, per lo sviluppatore, non per l'utente finale. Comprendere la cosa giusta da fare quando si rileva ogni eccezione è molto meglio che semplicemente applicare una regola d'oro o fare affidamento su una rete di sicurezza a livello di applicazione.

La codifica senza cervello è l'UNICO tipo di codifica errata. Il fatto che ritieni che ci sia qualcosa di meglio che può essere fatto in quelle situazioni dimostra che sei investito in una buona codifica, ma evita di provare a imprimere qualche regola generica in queste situazioni e capire il motivo di qualcosa da lanciare in primo luogo e cosa puoi fare per riprenderti.


6

So che questa è una vecchia domanda, ma nessuno qui ha menzionato l'articolo MSDN, ed è stato il documento che in realtà l'ha chiarito per me, MSDN ha un ottimo documento su questo, dovresti prendere delle eccezioni quando sono vere le seguenti condizioni:

  • Hai una buona comprensione del motivo per cui potrebbe essere generata l'eccezione e puoi implementare un recupero specifico, ad esempio chiedendo all'utente di inserire un nuovo nome file quando si cattura un oggetto FileNotFoundException.

  • È possibile creare e generare una nuova eccezione più specifica.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Si desidera gestire parzialmente un'eccezione prima di trasmetterla per ulteriore gestione. Nell'esempio seguente, viene utilizzato un blocco catch per aggiungere una voce a un registro errori prima di generare nuovamente l'eccezione.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Suggerirei di leggere l'intera sezione " Eccezioni e gestione delle eccezioni " e anche le migliori pratiche per le eccezioni .


1

L'approccio migliore è il secondo (quello in cui si specifica il tipo di eccezione). Il vantaggio di questo è che sai che questo tipo di eccezione può verificarsi nel tuo codice. Stai gestendo questo tipo di eccezione e puoi riprenderlo. Se è arrivata un'altra eccezione, significa che c'è qualcosa che non va che ti aiuterà a trovare bug nel tuo codice. L'applicazione finirà per bloccarsi, ma scoprirai che c'è qualcosa che hai perso (bug) che deve essere risolto.


1

Con Eccezioni, provo quanto segue:

In primo luogo, rilevo tipi speciali di eccezioni come divisione per zero, operazioni IO e così via e scrivo codice in base a ciò. Ad esempio, una divisione per zero, a seconda della provenienza dei valori che potrei avvisare l'utente (ad esempio un semplice calcolatore in quanto in un calcolo centrale (non gli argomenti) arriva in una divisione per zero) o per trattare silenziosamente quell'eccezione, registrando e continua l'elaborazione.

Quindi provo a rilevare le restanti eccezioni e registrarle. Se possibile, consentire l'esecuzione del codice, altrimenti avvisare l'utente che si è verificato un errore e chiedere loro di inviare un rapporto di errore.

Nel codice, qualcosa del genere:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}

1
Dividi per zero eccezioni e simili sono meglio gestiti controllando 0prima un numeratore, piuttosto che un try-catch. Inoltre, perché prendere Exceptionqui il generico ? È meglio lasciare che l'errore si risolva piuttosto che affrontarlo qui in tutti i casi in cui non te lo aspetti.
Keith,

Leggi meglio quello che ho scritto sull'esempio che ho dato - nota "non in argomenti". Ovviamente qualsiasi calcolatrice dovrebbe verificare gli argomenti forniti. Ciò di cui ho parlato riguardava i passi intermedi. A quel punto la verifica dell'argomento utente è già avvenuta. Inoltre, in alcune applicazioni è meglio evitare eccezioni a bolle. Alcune app dovrebbero trattare silenziosamente le eccezioni, mentre altre dovrebbero considerare le eccezioni come errori. Un web server per esempio dovrebbe essere eseguito anche quando si verificano eccezioni, in cui il software medico (ad esempio macchine a raggi X) dovrebbe interrompersi quando si verificano eccezioni.
Sorcerer86pt,

Nessuna app dovrebbe mai trattare silenziosamente le eccezioni. Occasionalmente hai un'eccezione che il codice può gestire, ma tale uso dovrebbe essere sia raro che specifico all'eccezione prevista. Il tuo esempio di server Web è scadente: dovrebbe avere impostazioni di configurazione che ti consentono di scegliere come vengono registrati gli errori e se vengono visualizzati con dettagli o solo una pagina HTTP 500, ma non devono mai ignorare silenziosamente gli errori.
Keith,

Sto cercando di capire cosa motiva davvero le persone ad aggiungere ancora un altro sinonimo di "goto". Ma per quanto riguarda la divisione per zero, questo sarebbe l'UNICO tipo di eccezione che posso vedere che giustifica il miglioramento del linguaggio. Perché? Perché potrebbe essere il caso che A) zero sia statisticamente un infinitesimale nel tuo set di dati e B) usare (consentire) un'eccezione potrebbe essere molto più efficiente, perché fare la divisione è un modo per testare un divisore zero. Quando A e B sono veri, l'esecuzione media del tuo programma sarà più veloce usando un'eccezione e potrebbe anche essere più piccola.
Mike Layton,

1

Il secondo approccio è valido.

Se non si desidera mostrare l'errore e confondere l'utente dell'applicazione mostrando l'eccezione di runtime (ovvero l'errore) che non è correlata a loro, è sufficiente registrare l'errore e il team tecnico può cercare il problema e risolverlo.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Ti consiglio di scegliere il secondo approccio per l'intera applicazione.


2
Il secondo approccio non mostra all'utente che si è verificato un errore, ad esempio se stavano salvando qualcosa non saprebbero che non è riuscito. catchi blocchi devono sempre chiamare throwper attivare l'eccezione o restituire qualcosa / visualizzare qualcosa che dica all'utente che l'azione non è riuscita. Vuoi ricevere la chiamata di supporto quando non riescono a salvare qualunque cosa sia, non 6 mesi dopo quando provano a recuperarla e non riescono a trovarla.
Keith,

0

Lasciare il blocco di cattura vuoto è la cosa peggiore da fare. Se si verifica un errore, il modo migliore per gestirlo è:

  1. Accedi al file \ database ecc.
  2. Prova a risolverlo al volo (magari provando un modo alternativo di fare quell'operazione)
  3. Se non riusciamo a risolvere il problema, avvisa l'utente che si è verificato un errore e ovviamente annulla l'operazione

0

Per me, la gestione delle eccezioni può essere vista come una regola aziendale. Ovviamente, il primo approccio è inaccettabile. Il secondo è migliore e potrebbe essere corretto al 100% se il contesto lo dice. Ora, ad esempio, stai sviluppando un componente aggiuntivo di Outlook. Se si aggiunge un'eccezione non gestita, l'utente di Outlook potrebbe ora conoscerlo poiché Outlook non si distruggerà da solo a causa di un plug-in non riuscito. E hai difficoltà a capire cosa è andato storto. Pertanto, il secondo approccio in questo caso, per me, è corretto. Oltre a registrare l'eccezione, potresti decidere di visualizzare un messaggio di errore per l'utente: lo considero una regola aziendale.


0

È consigliabile generare un'eccezione quando si verifica l'errore. Perché si è verificato un errore che non deve essere nascosto.

Ma nella vita reale puoi avere diverse situazioni quando vuoi nasconderlo

  1. Ti affidi a un componente di terze parti e desideri continuare il programma in caso di errore.
  2. Hai un caso aziendale che devi continuare in caso di errore

6
No. Non Non buttare Exception. Mai. Lancia una sottoclasse appropriata di Exceptiontutto ciò che desideri, ma mai Exceptionperché non fornisce assolutamente informazioni semantiche. Non riesco a vedere uno scenario in cui abbia senso lanciare, Exceptionma non una sua sottoclasse.
un CVn del


0

Il catchsenza alcun argomento è semplicemente mangiando l'eccezione e non serve a niente. Cosa succede se si verifica un errore fatale? Non c'è modo di sapere cosa è successo se si utilizza la cattura senza discussione.

Una dichiarazione catch dovrebbe catturare Eccezioni più specifiche come FileNotFoundExceptione poi alla fine dovresti catturare Exceptionche catturerebbe qualsiasi altra eccezione e le registrerebbe.


Perché un generale catch(Exception)alla fine? Se non te lo aspetti, è sempre consigliabile passare al livello successivo.
Keith,

1
@Keith sì hai ragione ... non ha senso catturare le eccezioni che non ti aspetti, ma puoi fare l'eccezione generale ai fini della registrazione ..
Anirudha,

0

A volte è necessario trattare le eccezioni che non dicono nulla agli utenti.

La mia strada è:

  • Catturare eccezioni non riscontrate a livello di applicazione (es. In global.asax) per eccezioni critiche (l'applicazione non può essere utile). Queste eccezioni non sto prendendo piede sul posto. Basta registrarli a livello di app e lasciare che il sistema faccia il suo lavoro.
  • Cattura "sul posto" e mostra alcune informazioni utili all'utente (immesso un numero errato, impossibile analizzare).
  • Prendi sul posto e non fare nulla per problemi marginali come "Verificherò le informazioni di aggiornamento in background, ma il servizio non è in esecuzione".

Sicuramente non deve essere la migliore pratica. ;-)


0

Posso dirti qualcosa:

Lo snippet n. 1 non è accettabile perché ignora l'eccezione. (lo sta ingoiando come se non fosse successo nulla).

Quindi non aggiungere un blocco catch che non fa nulla o semplicemente si ricomincia.

Il blocco di cattura dovrebbe aggiungere un valore. Ad esempio messaggio di output per l'utente finale o errore di registro.

Non utilizzare l'eccezione per la normale logica del programma di flusso. Per esempio:

ad es. validazione dell'input. <- Questa non è una situazione eccezionale valida, piuttosto è necessario scrivere il metodo IsValid(myInput);per verificare se l'elemento di input è valido o meno.

Codice di progettazione per evitare eccezioni. Per esempio:

int Parse(string input);

Se passiamo un valore che non può essere analizzato in int, questo metodo genererebbe un'eccezione, invece di scrivere qualcosa del genere:

bool TryParse(string input,out int result); <- questo metodo restituirebbe un valore booleano che indica se l'analisi ha avuto esito positivo.

Forse questo è un po 'fuori dalla portata di questa domanda, ma spero che questo ti aiuterà a prendere le giuste decisioni quando si tratta di try {} catch(){}ed eccezioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.