Perché non prendere le eccezioni generali

Il mio VS mi ha appena detto;

Avviso 2 CA1031: Microsoft.Design: modifica ‘Program.Main (string [])’ per rilevare un’eccezione più specifica rispetto a ‘Exception’ o rilanciare l’eccezione.

Perché dovrei farlo? Se lo faccio, e non rilevo tutte le eccezioni per gestirli, il mio programma si arresta in modo anomalo con la famosa schermata dei rapporti. Non voglio che i miei utenti ottengano tali errori!

Perché non dovrei rilevare tutte le eccezioni contemporaneamente per mostrare un avvertimento all’utente dicendo: “Qualcosa è andato storto, non preoccuparti, lo gestirò, sii paziente”?

Edit : Ho appena visto che ho un dupe qui, mi dispiace per quel Dupe

Edit2 : per chiarire le cose; Esco dal programma dopo che è stata rilevata un’eccezione! Non voglio che il mio utente veda la finestra di dialogo “Segnala a Microsoft” che compare quando viene sollevata un’eccezione non gestita in un’applicazione della console!

Ingerire le eccezioni è una pratica pericolosa perché:

  • Può far sì che l’utente pensi che qualcosa abbia avuto successo quando in realtà non ha funzionato.
  • Può mettere la tua applicazione in stati che non hai pianificato.
  • Complicano il debug, dal momento che è molto più difficile scoprire dove si è verificato l’errore quando si ha a che fare con comportamenti bizzarri / corrotti invece di una traccia di stack.

Come probabilmente puoi immaginare, alcuni di questi risultati possono essere estremamente catastrofici , quindi fare questo giusto è un importante habbit.

La migliore pratica

Prima di tutto, codifica in modo difensivo in modo che le eccezioni non si verifichino più del necessario. Sono computazionalmente costosi.

Gestire le eccezioni previste a livello granulare (ad esempio: FileNotFoundException ) quando ansible.

Per eccezioni impreviste, puoi fare una delle due cose:

  • Lasciali gonfiare normalmente e causare un incidente
  • Prendili e fallisci con grazia

Fallire con grazia?

Diciamo che stai lavorando in ASP.Net e non vuoi mostrare la schermata gialla della morte ai tuoi utenti, ma non vuoi che i problemi vengano nascosti al team di sviluppo.

Nelle nostre applicazioni, di solito rileviamo eccezioni non gestite in global.asax e poi facciamo il log e inviamo email di notifica. Mostriamo anche una pagina di errore più amichevole, che può essere configurata in web.config usando il tag customErrors .

Questa è la nostra ultima linea di difesa, e se finiamo per ricevere un’e-mail ci saltiamo subito sopra.

Quel tipo di modello non è lo stesso delle semplici eccezioni di ingoiare, in cui si ha un blocco Catch vuoto che esiste solo per “fingere” che l’eccezione non si sia verificata.

Altre note

In VS2010, è in arrivo qualcosa chiamato intellitrace che ti consentirà di inviare direttamente lo stato dell’applicazione a casa e di passare attraverso il codice, esaminare i valori delle variabili al momento dell’eccezione e così via. Sarà estremamente utile.

Poiché i programmi che inghiottono (intercettano) le eccezioni in modo indiscriminato (e quindi continuano), non possono essere invocati per fare ciò che sono tenuti a fare. Questo perché non hai idea di quale tipo di eccezione sia stata “ignorata”. Cosa accadrebbe se si verificasse un errore di overflow o di accesso alla memoria che causasse l’addebito di un importo errato su un conto finanziario? Cosa succede se dirige la nave nell’iceberg invece di allontanarsene? Errori imprevisti dovrebbero sempre causare la chiusura dell’applicazione. Questo costringe il processo di sviluppo a identificare e correggere le eccezioni che trova (gli arresti anomali durante le dimostrazioni sono una motivazione meravigliosa) e, in produzione, consente a sistemi di backup progettati in modo appropriato di reactjs quando il software sperimenta un’imprevista “inaspettata” a fare ciò che era progettato per fare.

EDIT: per chiarire le distinzioni tra componenti dell’interfaccia utente e componenti di servizi o middleware.

Nei componenti di servizio o middleware, in cui non vi è alcun utente che interagisca con il componente di codice all’interno dello stesso spazio di processo in cui è in esecuzione il codice, il componente deve “passare” l’eccezione a qualsiasi componente client abbia imitato la chiamata che sta attualmente elaborando . Non importa l’eccezione, dovrebbe fare ogni ansible tentativo di farlo. È comunque il caso, tuttavia, nei casi in cui si verifichi un’eccezione imprevista o imprevista, il componente deve infine terminare il processo in cui è in esecuzione. Per le eccezioni previste o previste, è necessario eseguire un’analisi del viluppo per determinare se, per tale specifica eccezione, il componente e il suo processo host possono continuare a funzionare (gestire le richieste future) o se deve essere chiuso.

Dovresti gestire le esatte eccezioni che sei in grado di gestire e far esplodere tutti gli altri. Se visualizza un messaggio all’utente, significa che non sai esattamente cosa puoi gestire.

Avendo lavorato su apparecchiature utilizzate dai soccorritori di emergenza, vorrei che l’utente vedesse un brutto messaggio di errore che ingerire accidentalmente un’eccezione che induce l’utente a credere che tutto sia “ok”. A seconda dell’applicazione, le conseguenze potrebbero essere qualsiasi cosa, dal nulla alla vendita persa a una catastrofica perdita di vite umane.

Se una persona dovesse prendere tutte le eccezioni, mostrare una finestra di dialogo di errore migliore e quindi chiudere l’applicazione, va bene .. ma se continueranno a correre dopo aver ingoiato un’eccezione sconosciuta, licenzierei una persona per quello. Non va bene. Mai.

Una buona codifica riguarda le pratiche che presuppongono che gli esseri umani commettano errori. Supponendo che tutte le eccezioni “critiche” siano state prese e gestite è una ctriggers idea.

Risposta semplice: devi risolvere il tuo bug. Trova il luogo che genera l’eccezione e, a meno che non sia fuori dal tuo controllo, risolvilo. Anche prendendo (senza ripensare) tutti i tipi di eccezione viola la neutralità delle eccezioni. In generale non si vuole fare questo (anche se la cattura delle eccezioni in main sembra un caso speciale)

Dal momento che il tuo messaggio di avviso mostra che questo è in Main (), assumerò che nei livelli più bassi, prendi solo eccezioni più specifiche.

Per Main (), prenderei in considerazione due casi:

  1. La tua build (debugging), in cui desideri ottenere tutte le informazioni sulle eccezioni che puoi ottenere: Non rilevare le eccezioni qui, quindi il debugger si interrompe e hai lo stack delle chiamate,
  2. Le tue pubblicazioni pubbliche, in cui desideri che l’applicazione si comporti normalmente: Catch Exception e visualizza un bel messaggio. Questo è sempre migliore (per l’utente medio) rispetto alla finestra ‘invia rapporto’.

Per farlo bene, basta controllare se DEBUG è definito (e definirlo, se VS non lo fa automaticamente):

 #if DEBUG yadda(); // Check only specific Exception types here #else try { yadda(); } catch (Exception e) { ShowMessage(e); // Show friendly message to user } #endif 

Disattiverei l’avviso relativo alla cattura delle eccezioni generali, ma solo per la tua funzione Main (), rilevare l’eccezione in qualsiasi altro metodo non è consigliabile, come già affermato da altri utenti.

C’è un modo per sopprimere determinati messaggi dall’analisi del codice . Ho usato questo per questo motivo esatto (rilevando l’eccezione generale per scopi di registrazione) ed è stato abbastanza utile. Quando aggiungi questo attributo, mostra che hai almeno riconosciuto che stai infrangendo la regola per un motivo specifico. Riceverai comunque il tuo avviso per i blocchi catch non corretti (rilevando l’eccezione generale per scopi diversi dalla registrazione).

MSDN SuppressMessageAttribute

Quando si rilevano eccezioni generali, si ottiene l’effetto collaterale di hide potenzialmente i problemi di runtime all’utente che, a sua volta, possono complicare il debug. Inoltre, rilevando un’eccezione generale, stai ignorando un problema (che probabilmente stai lanciando altrove).

Puoi impostare il tuo try catch per catturare diversi tipi di comportamento e gestire l’eccezione in base al tipo. Per la maggior parte dei metodi e delle proprietà nel framework, puoi anche vedere quali eccezioni sono in grado di lanciare. Quindi, a meno che non si stia rilevando un’eccezione da un blocco di codice estremamente piccolo, probabilmente dovresti rilevare eccezioni specifiche.

In VS puoi configurare una pagina di errore personalizzata per mostrare ai tuoi utenti quando qualcosa va storto invece di catturarlo in un try-catch. Presumo che tu stia usando VS che stai usando ASP .NET. In tal caso, aggiungi questo tag al tuo Web.Config sotto il tag System.Web:

  

È inoltre ansible rilevare tutte le eccezioni non rilevate nel file Global.asax (se non lo si è già fatto: fare clic con il pulsante destro del mouse su un progetto Web, selezionare Aggiungi elemento e cercarlo). Ci sono un sacco di gestori di eventi a livello di applicazione in quel file come “Application_Error” che cattura tutte le eccezioni che non vengono catturate dall’applicazione in modo da non dover utilizzare Try-Catch tutto il tempo. È utile utilizzarlo per inviare una e-mail se si verifica un’eccezione e se ansible reindirizzarla alla tua home page o qualcosa del genere se non si desidera utilizzare il tag customErrors in alto.

Ma alla fine non si desidera avvolgere l’intera applicazione in un tentativo di cattura né si desidera rilevare un’eccezione generale. I tentativi di cattura generalmente rallentano la tua applicazione e molte volte se rilevi un’eccezione generale di quanto potrebbe essere ansible che non sapresti che un bug esiste fino a mesi o anni dopo, perché il tentativo di cattura ti ha fatto trascurare.