2009-09-21 13 views
5

Le linee guida di programmazione .NET affermano che non dovremmo rilevare eccezioni generali. Suppongo che il seguente codice non è molto buona a causa del generale tipo di eccezione cattura:Eccezioni generali di catch .NET

private object CreateObject(string classname) 
    { 
     object obj = null; 
     if (!string.IsNullOrEmpty(classname)) 
     { 
      try 
      { 
       System.Type oType = System.Type.GetTypeFromProgID(customClass); 
       obj = System.Activator.CreateInstance(oType); 
      } 
      catch (Exception ex) 
      { 
       Log.Error("Unable to create instance for COM Object with class name " + classname + "\n" + ex.Message); 
      } 
     } 
     return obj; 
    } 

Nel codice seguente prendo particolari eccezioni, ma non tutti di loro e poi ri-generare l'eccezione nel caso in cui è diverso da le eccezioni non generiche. Tuttavia la funzione "CreateInstance" può generare molte eccezioni (ArgumentNullException, ArgumentException, NotSupportedException, TargetInvocationException, MethodAccessException, MemberAccessException, InvalidComObjectException, MissingMethodException, COMException, TypeLoadException).

È accettabile rilevare tutte le altre singole eccezioni? O c'è un modo migliore?

private object CreateObject(string classname) 
    { 
     object obj = null; 
     if (!string.IsNullOrEmpty(classname)) 
     { 
      try 
      { 
       System.Type oType = System.Type.GetTypeFromProgID(customClass); 
       obj = System.Activator.CreateInstance(oType); 
      } 
      catch (NotSupportedException ex) 
      { 
       Log.Error("...." + ex.Message); 
      } 
      catch (TargetInvocationException ex) 
      { 
       Log.Error("...." + ex.Message); 
      } 
      catch (COMException ex) 
      { 
       Log.Error("...." + ex.Message); 
      } 
      catch (TypeLoadException ex) 
      { 
       Log.Error("...." + ex.Message); 
      } 
      catch (InvalidComObjectException ex) 
      { 
       Log.Error("...." + ex.Message); 
      } 
      catch (Exception ex) 
      { 
       Log.Error("Unable to create instance for COM Object with class name " + classname + "\n" + ex.Message); 
       throw; 
      } 
     } 
     return obj; 
    } 
+0

Duplicato di: http://stackoverflow.com/questions/204814/is-there-any-valid-reason-to-ever-ignore-a-caught-exception –

risposta

9

È abbastanza accettabile rilevare eccezioni generali in .NET 2+ del framework.

- Modifica

L'unica ragione per cui non si dovrebbe, è se si può fare qualcosa di diverso con un'eccezione diversa. Se pianifichi di gestirli tutti uguali, prendi semplicemente il generale (o quello specifico che cerchi e lascia che qualcun altro salga).

+3

Sono d'accordo. A volte sento che lo prendiamo senza attirare l'eccezione generale agli estremi. –

+5

Non sono d'accordo. Questo lascerà la tua applicazione in uno stato eccezionale. Dovresti gestire solo le eccezioni su cui puoi fare qualcosa. Basta loggare e andare avanti è una cattiva idea. –

+0

@ justin.m.chase: questa è una posizione molto strana. Quindi, ogni volta che la tua app si arresta, preferiresti che i tuoi utenti visualizzino la pagina di errore generale .net invece della tua? –

1

Penso che sia possibile prendere tutte le eccezioni per intercettare un problema e visualizzare un messaggio amichevole per un utente piuttosto che un output di uno stack spaventoso.

Fintanto che non si limitano a ingoiare le eccezioni, ma registrarle e reagire in modo appropriato in background.

1

Se vuoi fare qualcosa di speciale con un diverso tipo di eccezione, prendilo in un blocco di cattura separato. Altrimenti non ha senso registrarli separatamente.

1

Non c'è una regola rigida che non dobbiamo usare eccezione generale, ma linea guida dice che ogni volta che abbiamo una possibilità di gestire un tipo specifico di eccezione non dovremmo andare a fare eccezione generica ..

Se siamo sicuri che tutte le eccezioni verranno gestite nello stesso modo, quindi utilizzare un'eccezione generica altrimenti andare per ogni specifica eccezione e generico dovrebbe venire in ultimo per qualche eccezione sconosciuta ..

ea volte nella tua applicazione si verifica un'eccezione che non è gestito nel codice a causa di una gestione delle eccezioni specifica, l'applicazione potrebbe andare in crash ..

in modo che il migliore approccio è gestire tutte eccezione specifica e poi dare un angolo ad eccezione generica anche in modo che l'applicazione rimanga stabile senza incidente ..

e quelli indesiderati eccezione generico può essere riportate o registrati da qualche parte per la versione futura miglioramento di applicazione ..

11

Come regola generale, non si dovrebbe intercettare le eccezioni a meno che:

  1. Hai una deroga specifica che è possibile gestire e fare qualcosa al riguardo. Tuttavia, in questo caso, dovresti sempre verificare se non dovresti cercare di rendere conto ed evitare l'eccezione in primo luogo.

  2. Sei al livello più alto di un'applicazione (ad esempio l'interfaccia utente) e non vuoi che il comportamento predefinito venga presentato all'utente. Ad esempio si potrebbe desiderare una finestra di dialogo di errore con un messaggio di stile "inviaci i tuoi registri".

  3. Si lancia nuovamente l'eccezione dopo averlo gestito in qualche modo, ad esempio se si ripristina una transazione DB.

In questo esempio, perché stai rilevando tutti questi tipi diversi? Mi sembra che il codice può essere solo:

try 
{ 
    System.Type oType = System.Type.GetTypeFromProgID(customClass); 
    return System.Activator.CreateInstance(oType); 
} 
catch (Exception ex) 
{ 
    Log.Error("...." + ex.Message); 

    //the generic catch is always fine if you then do this: 
    throw; 
} 

Quindi il problema è un esempio di regola (3) - si desidera registrare un'eccezione, ma poi continua e gettalo in su.

Tutti i diversi tipi ci sono in modo che in alcuni casi che si sa che è possibile gestire (vale a dire il caso 1). Per esempio supponiamo che tu sai che c'è una chiamata non gestito che funziona in tutto COMException - quindi il codice diventa:

try 
{ 
    System.Type oType = System.Type.GetTypeFromProgID(customClass); 
    return System.Activator.CreateInstance(oType); 
} 
catch (COMException cex) 
{ //deal with special case: 
    return LoadUnmanaged(); 
} 
catch (Exception ex) 
{ 
    Log.Error("...." + ex.Message); 

    //the generic catch is always fine if you then do this: 
    throw; 
} 
+0

Prendo tutti questi diversi tipi di eccezioni perché possono accadere (ad esempio, l'uso può passare un nome di classe non supportato o non registrato correttamente) e in tal caso non c'è un buon modo per verificare in anticipo un'eccezione (come può verificare ArgumentNullException). – Ioannis

+0

Sono sicuro che possono accadere tutti, ma a meno che non si abbia intenzione di fare qualcosa di specifico per quel tipo di eccezione, è meglio prendere solo l'eccezione generale e lanciarla. – Keith

+1

Questa risposta è esattamente giusta. La chiave è che stai lanciando l'eccezione generale verso l'alto non inghiottendoli. –

1

E 'considerato cattive pratiche di prendere abitualmente la base Exception quando si tratta di gestione degli errori, perché mostra un potenziale mancanza di comprensione di ciò che stai effettivamente trattando. Quando vedete un blocco di codice catturare Exception ciò che legge è "se qualcosa va storto qui, fatelo", dove tutto potrebbe andare da NullReferenceException a OutOfMemoryException.

Il pericolo nel trattare tutti gli errori è lo stesso, implica che non ti importa di quanto grave possa essere l'errore o di come potresti risolvere l'errore. Il 99% delle volte, quando vedo il codice catch(Exception ex), viene immediatamente seguito da un codice che ingoia l'eccezione, non dando alcun indizio sul motivo per cui le istruzioni non sono riuscite. Ugh.

L'esempio di registrazione degli errori mostra il modo corretto di utilizzare la base Exception, in una situazione in cui si desidera veramente trattare tutte le eccezioni allo stesso modo, solitamente al livello più alto di un'applicazione per impedire che l'applicazione termini in un brutto pasticcio.

1

Sono d'accordo con la risposta di Keith. Il vero problema con entrambi gli esempi di codice è che possono restituire null. Hai un metodo chiamato CreateObject che restituisce un'istanza di tipo object. Questo metodo non è riuscito per qualche motivo, ad esempio COMException. Entrambi gli esempi di codice restituiranno quindi null. Il codice chiamante ora è responsabile della verifica del risultato rispetto a null, oppure genererà una NullReferenceException.

Citando Framework Design Guidelines 2nd ed.:

Se un membro non può fare con successo ciò che è stato progettato per fare, si deve essere considerato un errore di esecuzione, e un'eccezione deve essere gettato.

Non ha fatto come suggerisce il nome. Gettare!

Il codice di Keith è corretto; è OK per registrare l'eccezione e rethrow.

Questo è un metodo privato, quindi le linee guida di progettazione non si applicano. Li applicherei comunque qui, perché - sporchi il tuo codice con "if (result == null)" quando invece puoi usare la gestione delle eccezioni?

+0

A volte è utile avere un metodo che proverà a creare un oggetto, ma restituirà null se non può; è spesso una buona idea, tuttavia, dare al metodo un nome che suggerisce che è ciò che farà. Microsoft preferisce che tali routine restituiscano un booleano per successo/fallimento e abbiano come parametro di riferimento una variabile di riferimento oggetto per memorizzare il nuovo oggetto, ma preferisco restituire il valore o null, poiché consente di definire una nuova variabile nell'istruzione che tenta di creare l'istanza. – supercat

+0

@supercat: Sarebbe bene se potessimo avere fiducia che altri sviluppatori (e noi stessi) controllassero sempre se il valore restituito è nullo ... – TrueWill

+0

Se chiamate una funzione chiamata TryGetFoo senza considerare che potrebbe fallire, meritano quello che ottengono. Potrebbero anche più facilmente ignorare il valore restituito (flag successo/fallimento) da un metodo "TryGetFoo" con pattern MS. La versione MS-pattern ha una caratteristica in alcune situazioni che può essere una cosa buona o cattiva: è possibile che una funzione lanci un'eccezione, ma imposta la variabile passata a qualcosa prima di farlo. Questo può essere buono se la variabile è un IDisposable, ma potrebbe causare confusione se il codice di ritorno del metodo create viene ignorato. – supercat

Problemi correlati