Eccezioni mirate per utilizzare le catture

10

Per un tipico if...else avvolto con la gestione delle eccezioni, è qualcosa di simile all'esempio seguente una pratica consigliata per evitare la duplicazione del codice?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

invece di ...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

So che c'è un leggero calo di prestazioni, ma mi chiedo se questa sia considerata una pratica accettabile. Al momento faccio il secondo metodo, specialmente nei casi in cui devo gestire le eccezioni specifiche in modo diverso, ma mi stavo chiedendo se il primo metodo sia appropriato per casi semplici.

    
posta grovesNL 20.04.2014 - 01:31
fonte

4 risposte

12

L'utilizzo della gestione delle eccezioni per il controllo del flusso è sconsigliato da Microsoft.

E a la tavola rotonda sull'argomento è disponibile.

Detto questo, C # lo supporta, e suppongo che dipenda dalla condizione riscontrata se un'eccezione è la risposta più appropriata.

    
risposta data 20.04.2014 - 02:15
fonte
6

Il risultato della performance è probabilmente trascurabile, come spiegato in questa risposta .

Quindi prendiamo l'idea che le prestazioni non siano un problema. Stai lanciando System.Exception , solo per spostare l'esecuzione nella clausola catch . Tuttavia lanciare un BadControlFlowThatShouldBeRewrittenException sarebbe probabilmente eccessivo.

Analizziamolo. Abbiamo:

  • Metodo GetDataFromServer (i nomi dei metodi dovrebbero essere PascalCase in C #), che può generare un'eccezione o restituire bool .
  • Se il risultato era true , esegui ProcessData .
  • Ritorno null altrimenti.

Sembra che il metodo in cui è scritto questo codice faccia semplicemente troppe cose. GetDataFromServer restituire un bool sembra un difetto di progettazione, mi aspetterei che quel metodo per restituisca i dati che riceve dal server , un po 'di IEnumerable<SomeType> che conterrebbe 0 o più elementi - es. percorso felice restituisce n elementi dove n > 0 , il percorso non-così-felice restituisce 0 elementi e il percorso infelice esplode con un'eccezione non gestita, qualunque essa sia.

Questo cambia il modo in cui appare il metodo, molto - ancora una volta è difficile dire se questo ha senso, perché il post originale ha solo un punto di uscita (e quindi non verrebbe compilato, come non tutti i percorsi di codice restituisce un valore ), quindi questa è solo un'ipotesi selvaggia:

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

Qui guardi ProcessData e vedi che sta iterando result , e restituisce null se non ci sono elementi in IEnumerable .

Ora perché il metodo restituisce null ? Il server era giù? C'è un bug nella query? La stringa di connessione utilizza le credenziali errate? Ogni volta che GetDataFromServer scoppia con un'eccezione che non ti aspetti, la stai inghiottendo, spingendola sotto il tappeto e restituendo un valore di null . Consiglierei di rilevare eccezioni specifiche in questo caso e di registrare tutto il resto; il debugging sarà molto più facile in questo modo.

Con una clausola generale catch che non cattura l'eccezione, diventa piuttosto difficile diagnosticare qualsiasi cosa. Lo farei minimamente invece:

catch(Exception e)
{
    return null;
}

Ora puoi almeno interrompere e ispezionare e se le cose vanno male.

TL; DR : no, le eccezioni di lancio e cattura per il controllo del flusso non sono una buona idea.

    
risposta data 22.04.2014 - 16:15
fonte
2

nella tua prima risposta c'è un colpo di performance che non ha bisogno di essere lì.

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

quando esci dall'istruzione if per entrare nell'istruzione Catch quando non devi fare in modo che il codice cambi direzione, per così dire.

se vuoi return null; fallo nell'istruzione else non in un catch che viene catturato dopo essere stato gettato dall'istruzione else.

Probabilmente non si applica al tuo codice Real , ma per il codice generico che hai fornito si applica.

Gli standard dicono che non dovresti farlo.

Gli standard dicono che dovresti farlo in questo modo, (di nuovo basato sul codice generico dato in OP)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

e dal momento che non hai eccezioni specifiche che stai catturando, non dovresti nemmeno provare a catturare qui.

vuoi vedere le eccezioni quando si verificano in modo da poter risolvere il problema che crea l'eccezione.

    
risposta data 22.04.2014 - 17:56
fonte
1

Perché non molto più semplice:

if (!GetDataFromServer()) return null;
ProcessData();

Se un gestore di eccezioni sta per esistere dovrebbe essere in ProcessData ()

    
risposta data 22.04.2014 - 19:15
fonte

Leggi altre domande sui tag