2011-12-31 14 views
17

ho avuto la domanda: "Che cosa si preferisce, la gestione delle eccezioni o se-condizione"se condizionata vs gestore di eccezioni

per un'intervista. La mia risposta è stata che i gestori di eccezioni sono preferiti solo per circostanze eccezionali come un errore di autorizzazione del disco sulla scrittura di file. L'intervistatore sembrava aspettarsi qualche altra risposta. Qual è la risposta corretta?

MODIFICA: qualsiasi esempio particolare in cui la gestione delle eccezioni è comunemente utilizzata quando una condizione if sarebbe stata più appropriata?

+5

"L'intervistatore sembrava aspettarsi qualche altra risposta" - allora perché non gliel'hai chiesto? Sono sempre più impressionato da una domanda che da una risposta durante l'intervista ... –

risposta

23

Poiché questa domanda è contrassegnata come "C#", possiamo fare riferimento alle Linee guida di progettazione di .NET Framework come un buon punto di partenza per rispondere a questi tipi di domande. Questa è la guida fornita su MSDN sotto "Exception Throwing":

Non utilizzare eccezioni per il normale flusso di controllo, se possibile. Tranne per errori di sistema e operazioni con potenziali condizioni di gara, i progettisti di strutture devono progettare API in modo che gli utenti possano scrivere il codice che non genera eccezioni. Ad esempio, è possibile fornire un modo per verificare le precondizioni di prima di chiamare un membro in modo che gli utenti possano scrivere il codice che non genera eccezioni.

Ecco un esempio di una cattiva pratica dove un'eccezione viene gestita, ma può quasi sempre essere evitato:

public int? GetItem(int index) 
{ 
    int? value = null; 
    try 
    { 
     value = this.array[index]; 
    } 
    catch (IndexOutOfRangeException) 
    { 
    } 

    return value; 
} 

Questo sembra artificioso ma vedo codice come questo molto spesso dai programmatori più recenti. Supponendo una corretta sincronizzazione intorno a letture e scritture su array, questa eccezione può essere evitata al 100% in modo deterministico. Dato che, un modo migliore per scrivere che il codice sarebbe il seguente:

public int? GetItem(int index) 
{ 
    int? value = null; 

    // Ensure the index is within range in the first place! 
    if (index >= 0 && index < this.array.Length) 
    { 
     value = this.array[index]; 
    } 

    return value; 
} 

Ci sono altri casi in cui non si può ragionevolmente evitare eccezioni e solo bisogno di gestirli. Ciò è più comune quando si ha a che fare con risorse esterne come file o connessioni di rete a cui si potrebbe potenzialmente perdere l'accesso o il contatto in qualsiasi momento. Esempio da WCF:

public void Close() 
{ 
    // Attempt to avoid exception by doing initial state check 
    if (this.channel.State == CommunicationState.Opened) 
    { 
     try 
     { 
      // Now we must do a (potentially) remote call; 
      // this could always throw. 
      this.channel.Close(); 
     } 
     catch (CommunicationException) 
     { 
     } 
     catch (TimeoutException) 
     { 
     } 
    } 

    // If Close failed, we might need to do final cleanup here. 
    if (this.channel.State == CommunicationState.Faulted) 
    { 
     // local cleanup -- never throws (aside from catastrophic situations) 
     this.channel.Abort(); 
    } 
} 

Anche nell'esempio di cui sopra, è bene controllare che l'operazione che si sta per fare almeno ha una possibilità di successo. Quindi c'è ancora un controllo if(), seguito dalla logica di gestione delle eccezioni appropriata.

+0

Nell'esempio 'GetItem', il chiamante non è in grado di determinare se è stato fornito un 'index' non valido, o se' array [index] 'contiene un valore' null'. Quindi la domanda rimane ciò che è meglio. Dovresti lanciare un'eccezione se è stato utilizzato un indice non valido? O semplicemente restituirai un valore 'nullo' senza alcuna indicazione che si sia verificato un errore? Anche l'utilizzo di un indice non valido su un array causerà un'eccezione, non restituirà il valore predefinito del tipo di array! – comecme

+2

@comecme: In questo esempio, è possibile assumere che 'array' è stato dichiarato come' int [] ', quindi' null' può significare solo che il valore non esiste (out o range). Sì, il chiamante non lo saprà, ma l'implementatore * saprà * e non dovrebbe usare eccezioni come flusso di controllo che era il punto dell'esempio. È valido restituire un valore predefinito senza generare un'eccezione, sebbene questo modello sia generalmente previsto in un metodo 'TryXxx', come discusso qui: http://msdn.microsoft.com/it-it/library/ms229009.aspx – bobbymcr

10

La gestione delle eccezioni è un'operazione pesante e costosa per quanto riguarda le prestazioni. Se è possibile evitare l'intercettazione di un'eccezione se si utilizza correttamente if else che può aumentare le prestazioni dell'applicazione

D'altra parte, se il blocco altro ha più senso per il lettore di codice. Sono facili da capire e da mantenere rispetto al blocco di prova eccezionale. Essi descrivono il flusso del programma in maniera più elegante

E infine, come lei ha detto La gestione delle eccezioni dovrebbe essere per situazioni incerte o per casi eccezionali, non dovrebbe essere la scelta di default

Modifica

Un brutto comune pratica ho visto in alcuni posti è questa

try 
{ 
    string str = "Some String" 
    int i = Convert.ToInt32(str); 
} 
catch (Exception ex) 
{ 
     MessageBox.Show("Invalid input");   
} 

Ora provare cattura può essere facilmente evitato in questa custodia utilizzando if else

string str = "Some String" 
    int i; 
    if(!int.TryParse(str, out i)) 
    { 
     MessageBox.Show("Invalid input");   
    } 
+1

Normalmente la classe che converte la stringa non sarebbe la classe che visualizza i messaggi di errore. Ecco perché esistono eccezioni: possono essere catturate a un livello più alto. – comecme

4

La risposta corretta è solo quella che hai dato.

Per maggiore specificità, dovresti aver detto qualcosa sull'effetto di "Uso le affermazioni laddove possibile a causa del sovraccarico delle eccezioni di cattura e lancio".

0

Se si conosce l'accesso esatto del programma e si conoscono gli errori che possono verificarsi, è possibile scrivere l'istruzione if-else o in altri casi è possibile lasciare le cose per cercare di rilevare la gestione delle eccezioni.

2

Normalmente preferisco utilizzare un valore speciale non definito (ad esempio null per oggetti) per indicare che alcuni calcoli non potrebbero produrre un risultato valido a causa di un input non valido. Ciò significa che il mio codice potrebbe determinare e segnalare correttamente che i dati di input non sono validi e che non è possibile produrre risultati significativi.

Preferisco utilizzare un'eccezione quando il mio codice non può completare il calcolo richiesto, ad es. se un file contenente alcuni dati richiesti non esiste, se non può connettersi a un database.

Quindi concettualmente:

  • risultato indefinito (più se-condizione): programma determina con successo che non v'è alcuna uscita valida per l'ingresso data.
  • Eccezione (più try-catch): il programma non può completare il calcolo a causa di un errore nell'applicazione non correlato all'input.
Problemi correlati