Aumentare di proposito le eccezioni per l'uso del pescato


10

Per un tipico if...elsepacchetto con gestione delle eccezioni, qualcosa come il seguente esempio è 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 successo nelle prestazioni, ma mi chiedo se questa sia considerata una pratica accettabile. Attualmente faccio il secondo metodo, specialmente nei casi in cui ho bisogno di gestire in modo diverso eccezioni specifiche, ma mi chiedevo se il primo metodo fosse appropriato per casi semplici.


se il metodo è abbastanza piccolo rimuoverò l'altro e restituirò null al di fuori del blocco trycatch, quindi devo restituire null solo una volta.
Fabio Marcolini,

Risposte:


12

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

E una tavola rotonda sull'argomento è disponibile.

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


1
Mi sembra che questo genere di cose stia solo cercando di non usare gli eventi.
radarbob,

@radarbob: in che modo gli eventi sono correlati a questo?

@grovesNL - Lanciare un'eccezione in un punto specifico per chiamare un determinato metodo in un blocco catch? Quacks mi piace come un evento.
radarbob,

@radarbob: non è un evento. Ci sono molti casi d'uso di esempio in cui questo verrebbe usato, come discusso nel link della tavola rotonda della risposta.

1
@radarbob Solo un po 'di chiarimento, le eccezioni sono state progettate come un modo per segnalare al chiamante che si è verificato qualcosa che il metodo chiamato non è in grado di gestire. Tuttavia, è necessario ascoltare un evento. Un'eccezione è un'interruzione forzata del normale flusso di un programma. Un'eccezione non rilevata provoca l'interruzione dell'intera applicazione.

6

Il colpo di scena è probabilmente trascurabile, come spiegato in questa risposta .

Quindi andiamo con l'idea che le prestazioni non siano un problema. Stai lanciando System.Exception, solo per spostare l'esecuzione nella catchclausola . Lanciare a BadControlFlowThatShouldBeRewrittenExceptionsarebbe probabilmente eccessivo.

Analizziamo questo. Abbiamo:

  • Metodo GetDataFromServer(i nomi dei metodi devono essere PascalCase in C #), che può eventualmente generare un'eccezione o restituire a bool.
  • Se il risultato è stato true, esegui ProcessData.
  • Ritorna nullaltrimenti.

Sembra che il metodo in cui è scritto questo codice, stia semplicemente facendo troppe cose. GetDataFromServerrestituendo un boolaspetto simile a un difetto di progettazione, mi aspetterei che quel metodo restituisca i dati che sta ricevendo dal server , alcuni IEnumerable<SomeType>che conterrebbero 0 o più elementi - vale a dire il percorso felice restituisce n elementi in cui n> 0 , non così felice path restituisce 0 elementi e il percorso infelice esplode con un'eccezione non gestita, qualunque essa sia.

Ciò cambia l'aspetto del metodo, abbastanza - ancora una volta è difficile capire se questo ha senso, perché il post originale ha solo un punto di uscita (e quindi non si compila, poiché non tutti i percorsi di codice restituiscono un valore ), quindi questa è solo un'ipotesi selvaggia:

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

Qui guarderesti ProcessDatae vedresti che sta iterando il result, e ritorna nullse non ci sono elementi nel IEnumerable.

Ora, perché il metodo sta tornando null? Server inattivo? C'è un bug nella query? La stringa di connessione utilizza credenziali errate? Ogni volta che GetDataFromServeresplode con un'eccezione che non ti aspetti, lo stai ingoiando, spingendolo sotto il tappeto e restituendo un nullvalore. In questo caso, consiglierei di cogliere eccezioni specifiche e di registrare tutto il resto; il debug sarà molto più semplice in questo modo.

Con una catchclausola generale che non cattura l'eccezione, diventa abbastanza difficile diagnosticare qualsiasi cosa. Invece lo farei minimamente:

catch(Exception e)
{
    return null;
}

Ora puoi almeno rompere e ispezionare ese le cose vanno male.


TL; DR : No, lanciare e catturare le eccezioni per il controllo del flusso non è una buona idea.


Questa risposta dimostra esattamente il motivo per cui ho cercato di mantenere generico il mio codice: non volevo elencare ogni singola eccezione che ho effettivamente fatto nel mio codice; Non volevo elencare i nomi dei metodi attuali; Non volevo elencare la dichiarazione del metodo; Non volevo suggerimenti di sintassi. Avevo una sola domanda sull'opportunità di lanciare eccezioni per il controllo del flusso, a cui prontamente ha risposto B2K. Sarei felice di discuterne su meta.

3
sembra che questo avrebbe dovuto essere una domanda per i programmatori allora. esaminiamo il codice, non le idee.
Malachi,

2

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

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

quando si esce dall'istruzione if per entrare nell'istruzione Catch quando non è necessario che il codice cambi direzione, per così dire.

se si desidera return null; farlo nell'istruzione else non in una cattura che viene catturata dopo essere stata lanciata dall'istruzione else.

Probabilmente non si applica al tuo codice reale , ma si applica al codice generico che gli hai dato.

Gli standard dicono che non dovresti farlo.

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

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

e poiché non hai eccezioni specifiche che stai rilevando, non dovresti nemmeno provare qui.

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


1

Perché non molto più semplice:

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

Se esiste un gestore di eccezioni, dovrebbe trovarsi in ProcessData ()


Perché non dovrei voler passare le eccezioni ProcessData()al livello più alto?
GroveNL

@grovesNL Non è stato fatto nulla di utile con l'eccezione qui.
Loren Pechtel,

1
Come mai? Se ProcessData()genera un'eccezione ora non viene gestita. Lo voglio return nulla questo livello se ProcessData()genera un'eccezione, senza modificarsi ProcessData().
GroveNL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.