Perché try-catch in main () è cattivo?

Qualcuno potrebbe spiegarmi perché è considerato inopportuno avere un try-catch nel metodo main () per catturare eventuali eccezioni non gestite?

[STAThread] static void Main() { try { Application.Run(new Form1()); } catch (Exception e) { MessageBox.Show("General error: " + e.ToString()); } } 

Ho capito che questa è una ctriggers pratica, ma non sono sicuro del perché.

Non penso che sia necessariamente una ctriggers pratica. Tuttavia, ci sono alcuni avvertimenti …

Credo che il punto di chi ha chiamato questa “ctriggers pratica” è stato quello di rinforzare l’idea che dovresti catturare le eccezioni più vicine al punto in cui si verificano (ad esempio, il più alto ansible nello stack di chiamate / appropiato). Un gestore di eccezioni generico non è in genere una buona idea perché riduce drasticamente il stream di controllo disponibile. La gestione delle eccezioni a grana grossa non è una soluzione ragionevole per programmare la stabilità. Sfortunatamente, molti sviluppatori principianti pensano che lo siano, e adottano approcci come questa affermazione generale di prova.

Dicendo questo, se hai utilizzato la gestione delle eccezioni in modo corretto (in modo preciso e specifico) nel resto del tuo programma, e gestisci gli errori di conseguenza (piuttosto che juist che visualizza una finestra di errore generica), prova generale -catch per tutte le eccezioni nel metodo Main è probabilmente una cosa utile da avere. Un punto da notare qui è che se stai riproducendo in modo riproducibile i bug in questo try-catch principale, allora hai un bug o qualcosa non va nella gestione delle eccezioni localizzata.

L’utilizzo principale di questo try-catch con Main sarebbe puramente per evitare che il programma si arresti in modo anomalo in circostanze molto insolite, e dovrebbe fare appena più di un messaggio di errore fatale (vagamente) user-friendly all’utente, come pure come possibilmente loggando l’errore da qualche parte e / o inviando un bug report. Quindi per concludere: questo metodo ha i suoi usi, ma deve essere fatto con grande cura, e non per le ragioni sbagliate.

Bene, questo metodo catturerà solo le eccezioni generate nel thread principale. Se si utilizzano entrambi gli eventi Application.ThreadException e AppDomian.UnhandledException , sarà ansible rilevare e registrare tutte le eccezioni.

Non vedo come sia una ctriggers pratica.

Lasciare che il programma si arresti in modo anomalo con un errore di eccezione non gestita non infonderà alcuna confidenza nei tuoi utenti finali.

Forse qualcun altro potrebbe fornire una vista contraria.

Aggiornamento: Ovviamente dovrai fare qualcosa di utile con l’eccezione.

  1. registralo
  2. mostra all’utente una finestra di dialogo che dice PERCHE ‘l’applicazione sta uscendo (in testo normale, non in una pila)
  3. qualcos’altro che ha senso nel contesto della vostra applicazione.

Non penso che sia una ctriggers pratica in sé e per sé. Penso che la ctriggers pratica sarebbe se questo fosse l’unico blocco try / catch che hai nella tua applicazione.

In antichità, l’inserimento di un try / catch in C ++ ha causato una penalità di prestazioni piuttosto pesante, e posizionarne una attorno a main significherebbe memorizzare informazioni extra sullo stack per tutto, il che è stato di nuovo negativo per le prestazioni.

Ora i computer sono più veloci, i programmatori meno dipendenti dalle prestazioni e i runtime sono costruiti in modo migliore, quindi non è più così male (ma potresti ancora pagare un po ‘di più, non avere un benchmark con il suo effetto in anni). Quindi è il vecchio folklore come iterare controcorrente (i compilatori in realtà risolvono comunque l’iterazione per te al giorno d’oggi). In C # va benissimo, ma sembrerebbe incerto a qualcuno di 10 anni fa.

Qualsiasi eccezione che arriva a Main() è probabilmente fatale.

Se fosse qualcosa di facile, avrebbe dovuto essere gestito più in alto. Se era qualcosa fuori dal tuo controllo, come OutOfMemoryException , il programma dovrebbe bloccarsi.

Le applicazioni Windows che si bloccano in modo anomalo hanno un modo standard per farlo, triggersno la finestra di dialogo Segnalazione errori di Windows . (Probabilmente l’hai visto prima). È ansible iscriversi per ricevere i dati di arresto anomalo quando ciò accade.

Non sono sicuro che sia una ctriggers pratica. Quello che vuoi fare è assicurarti che l’eccezione e lo stato attuale del programma quando si blocca finisce nelle mani di uno sviluppatore, preferibilmente loggato con data, ora e l’utente che stava lavorando con esso. Fondamentalmente – vuoi assicurarti che il tuo team abbia tutte le informazioni di cui hanno bisogno per eseguire il debug del problema, indipendentemente dal fatto che l’utente si rivolga o meno a loro in merito all’incidente. Ricorda che molti utenti non potranno, in effetti, contattare l’assistenza in caso di incidente.

La ctriggers pratica qui sarebbe prendere l’eccezione, mostrando una semplice finestra di dialogo “Errore” e chiudendo l’applicazione. In tal caso, lo stato di tale eccezione viene perso per sempre.

Da un punto di vista del debug, questo può rendere la vita più difficile, in quanto rende ogni eccezione gestita da un utente. Questo cambia il comportamento del debugger, a meno che non si interrompa su eccezioni non gestite, che potenzialmente ha altri problemi.

Detto questo, penso che questa sia una buona pratica al momento del rilascio. Inoltre, ti consiglio di ascoltare anche gli eventi AppDomain.UnhandledException e Application.ThreadException . Questo ti permetterà di intrappolare anche più eccezioni (come alcune eccezioni di sistema che non verranno catturate nel tuo gestore “globale” sopra).

Ciò consente di registrare gli errori e fornire all’utente un messaggio buono e pulito.

Cambialo in questo ed è tutto a posto

 catch(Exception ex) { YourLoggingSystem.LogException(ex); } 

Ovviamente, questa linea non dovrebbe MAI essere colpita in quanto avrete altri gestori di eccezioni in tutto il codice che catturano le cose con un contesto molto più ampio.

La gestione delle eccezioni di primo livello è piuttosto essenziale, ma consiglio di utilizzare:

 Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod); 

Tuttavia, questo catturerà solo eccezioni sul thread della GUI (molto simile al tuo blocco try..catch) – dovresti usare un codice simile per ogni nuovo thread che inizi a gestire eventuali eccezioni impreviste.

Maggiori informazioni qui .

Hai l’unica eccezione che catturerà tutto. Quindi se hai qualche eccezione non gestita nel tuo codice, non le vedrai mai.

Sul lato positivo, la tua applicazione non si bloccherà mai!

Se questo comportamento è necessario, è necessario disporre di registrazioni e rapporti sufficienti per consentire sia all’utente che a te, in qualità di sviluppatore, di sapere cosa è successo e recuperare o uscire nel modo più agevole ansible.

Non sto dicendo che è una ctriggers pratica, l’unica cosa che farei diversamente è usare l’evento integrato per questo:

  Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show(e.Exception.Message); //or do whatever... } 

Penso che questo sia scoraggiato perché le eccezioni vengono catturate solo una volta e possono esserci più cose, come i thread in background, che devono sapere se un processo si verifica.

È un’app WinForms? Forms.Application.Run genera eventi ogni volta che un thread genera un’eccezione non gestita. I documenti MSDN provano a spiegarlo, ma il gestore che mostrano non funziona! Leggi l’ esempio aggiornato dal sito UE di WinForms.

Se il tuo programma cerca di continuare a funzionare nonostante un catch-all catching chissà quale tipo di violazione delle ipotesi sotto, è in una zona pericolosa per cose come lo sfruttamento remoto dei difetti di sicurezza (buffer overflow, heap corruption). Metterlo in un loop e continuare a correre è una grande bandiera rossa per la qualità del software.

Uscire il prima ansible è il migliore, ad es. Exit (1). Il log and exit è buono anche se leggermente più rischioso.

Non mi credi? La mitra Common Weakness Enumeration (CWE) è d’accordo . Strettamente correlato è il suo consiglio contro la cattura del dereferenziamento del puntatore NULL in questo modo.

Potrei fare una lunga spiegazione, ma stai meglio leggendo la risposta del blog del team FxCop .