c# - altrimenti o ritorno?




.net (13)

Dipende da cosa sono "risultato", "processo1" e "processo2".

Se process2 è la conseguenza logica di "risultato" falso; dovresti andare per il codice 1. Questo è il modello più leggibile se process1 e process2 sono alternative equivalenti.

if (do_A_or_B = A)
  A()
else
  B()

Se il risultato è una condizione "no-go" e "process1" è semplicemente una pulizia necessaria in tale condizione, è necessario scegliere il Codice 2. È lo schema più leggibile se "process2" è l'azione principale della funzione.

if (NOT can_do_B)
{
  A() 
  return
}

B()

Quale dei due seguenti è il migliore per le prestazioni e la pratica standard. In che modo .NET gestisce internamente questi due frammenti di codice?

code1

If(result)
{
  process1();
}
else
{
  process2();
}

O codice 2

If(result)
{
   process1();
   return;
}
process2();

Dipende dal contesto.

Se questo è in una funzione che al calcolo di un valore, restituisci quel valore non appena lo hai (opzione 2). Stai dimostrando di aver fatto tutto il lavoro necessario e se ne stanno andando.

Se si tratta di codice che fa parte della logica del programma, è meglio essere il più precisi possibile (opzione 1). Qualcuno che osserva l'opzione 1 saprà che intendi (fai questo O quello), dove l'opzione 2 potrebbe essere un errore (in questa condizione fallo QUINDI SEMPRE farlo - lo correggerò solo per te!). Aveva quello prima.

Quando vengono compilati, questi sono solitamente gli stessi, ma non siamo interessati alle prestazioni. Si tratta di leggibilità e manutenzione.


Entrambi gli stili sono all'ordine del giorno e le guerre di religione sono state combattute su di loro. :-)

Normalmente lo faccio:

  • Se il test sta esprimendo la semantica del contratto di metodo, ad esempio controllando i parametri di input per la validità, quindi scegliere l'opzione 2.
  • Altrimenti, scegli l'opzione 1.

Tuttavia, probabilmente una regola più importante è "che è più leggibile e / o mantenibile per il prossimo sviluppatore che guarda il codice?".

La differenza di prestazioni è trascurabile, come altri hanno già detto.


Entrambi saranno compilati nello stesso IL per la modalità Release (potrebbero esserci alcuni diversi operandi Nop in Debug ..) e come tali non avranno alcuna differenza di prestazioni. Questo è totalmente il modo in cui tu e il tuo team sentite che il codice è più facile da leggere.

Ero nel campo contro l'uscita anticipata, ma ora sento che può rendere il codice molto più semplice da seguire.

// C#
public static void @elseif(bool isTrue)
{
    if (isTrue)
        Process1();
    else
        Process2();
}
// IL
.method public hidebysig static void  elseif(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::elseif


// C#
public static void @earlyReturn(bool isTrue)
{
    if (isTrue)
    {
        Process1();
        return;
    }
    Process2();
}
// IL
.method public hidebysig static void  earlyReturn(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::earlyReturn

La differenza di prestazioni, se presente, è trascurabile in tutti i casi normali.

Una pratica standard (tra le altre) consiste nel cercare di mantenere un singolo punto di uscita da un metodo, in modo tale che i colloqui favoriscano la prima alternativa.

L'implementazione effettiva per il return nel mezzo è più probabile che faccia un salto alla fine del metodo, dove è il codice per avvolgere il frame dello stack per il metodo, quindi è probabile che il codice eseguibile finale sia identico per i due codici.


Non posso dire delle prestazioni, ma il Codice 1 mi sembra molto più chiaro e logico. Saltare fuori da una funzione nel mezzo di un blocco if sembra abbastanza confuso ed è facile da trascurare.


Penso che la seconda opzione sia migliore per i casi di molte condizioni (come la convalida). Se usi il primo in questi casi otterrai una brutta rientranza.

 if (con){
    ...
    return;
 }
 if (other con){
    ...
    return;
 }
 ...
 return;

Penso che non dovresti preoccuparti delle prestazioni qui. In questo caso, la leggibilità e la manutenibilità sono molto più importanti.

Attenersi a un punto di uscita per una routine è una buona pratica.

Tuttavia, a volte i ritorni multipli rendono il codice molto più chiaro, specialmente quando si ha un certo numero di test vicino all'inizio del codice (cioè si verifica se tutti i parametri di input sono nel formato corretto) per i quali un 'if-true' dovrebbe portare a un ritorno.

vale a dire:

if (date not set) return false;
age = calculateAgeBasedOnDate();
if (age higher than 100) return false;
...lots of code...
return result;

Personalmente mi piace sempre tornare al più presto, quindi vorrei andare per qualcosa come:

if (result)
{
    // do something
    return;
}

// do something if not result

Per quanto riguarda le prestazioni, dubito che entrambi abbiano dei vantaggi rispetto all'altro, in realtà si tratta di leggibilità e gusto personale. Presumo che .NET ottimizzerebbe il tuo primo blocco di codice con qualcosa come sopra.


Se c'è un codice comune, questo deve essere eseguito dopo il blocco if / else, quindi l'opzione 1.

Se il blocco if-else è l'ultima cosa da fare in una funzione, allora l'opzione 2.

Personalmente uso sempre l'opzione 1. Se c'è un return stateent, viene dopo il blocco else


Se rimuovi le parentesi graffe attorno al codice rimanente della seconda versione, è esattamente quello che uso. Preferisco rendere ovvia la parte di validazione anticipata di una funzione, e poi posso mettermi al lavoro.

Detto questo, è una questione di opinione. Finché sei coerente su questo, sceglierne uno e seguitelo.

edit: A proposito delle prestazioni, l'IL emesso è esattamente lo stesso. Scegli uno o l'altro per lo stile, non c'è penalità per nessuno dei due.


Tendo ad avere più punti di uscita da una funzione. Personalmente penso che sia più chiaro e in alcuni casi può essere più veloce. Se controlli qualcosa e poi restituisci il programma non eseguirai alcun comando di sinistra. Poi, come ha detto HZC, se lavori su applicazioni multi-thread, allora la tua ripresa migliore potrebbe essere il tuo primo esempio. Ad ogni modo per piccoli pezzi di codice non farà alcuna differenza (probabilmente nemmeno per alcuni più grandi). La cosa più importante è che scrivi come ti senti a tuo agio.


Vorrei usare il Code 1 , perché se aggiungo qualcosa dopo la dichiarazione if , sono comunque positivo che verrà eseguito, senza che io debba ricordare di rimuovere la clausola return da dove si trova nel Code 2 .







.net