Le migliori pratiche riguardanti l'uscita a Delfi [duplicato]

16

Un collega e io stiamo discutendo di ciò che è meglio. Entrambi i concetti funzionano e funzionano bene, ma c'è un consenso generale sul non effettuare una chiamata per uscire?

Cosa c'è di meglio?

Per chiamare l'uscita all'interno di una procedura per evitare di fare il resto del codice come in ...

if Staging.Current = nil then exit  

DoSomethingA(FileNameA);  
DoSomethingB(FileNameB);  
Staging.DeleteCurrent;

o per non chiamare exit e invece avvolgerlo all'inizio e alla fine

if Staging.Current <> nil then  
begin   
  DoSomethingA(FileNameA);  
  DoSomethingB(FileNameB);  
  Staging.DeleteCurrent;   
end;

Entrambi funzionano. Preferisco usare la dichiarazione di uscita dal momento che risulta in un minor numero di righe di codice e mi sembra più pulito, ma c'è qualche ragione o consenso tra i programmatori per evitare di usare exit per uscire da una procedura?

    
posta Tim 19.05.2011 - 16:04
fonte

10 risposte

33

Questa è una domanda di guerra di tipo religioso. Per riferimento, la discussione definitiva sullo Stack Overflow è disponibile qui: link

Molte persone si oppongono ai metodi che hanno più punti di uscita. Sostengono che rende più difficile ragionare sul comportamento di un metodo.

D'altra parte, gli altri prendono il punto di vista che una volta che un metodo ha completato il suo lavoro, è ragionevole che smetta. Coloro che tengono questo punto di vista sosterrebbero che una dichiarazione di ritorno C, ad es. return 42 è chiaro e ragionevole ovunque in una funzione.

Personalmente ritengo che ci sia una chiara distinzione tra il codice che esce volutamente da molti punti diversi e il codice presentato nella tua domanda che è nota come clausola di protezione .

Uno dei grandi vantaggi delle clausole di protezione è quando si hanno più test. Il codice scritto senza clausole di salvaguardia si traduce in indentazione significativa che la maggior parte delle persone concordano essere considerato dannoso.

È mia opinione che l'opinione di consenso sia che le clausole di salvaguardia sono migliori di qualsiasi altra alternativa.

    
risposta data 19.05.2011 - 16:29
fonte
12

L'unica ragione (oltre alle tue preferenze) per non utilizzare exit sono le linee guida di programmazione. Se nessuna linea guida del genere esiste, sentiti libero di usare qualsiasi cosa si adatta alle tue esigenze o rende il tuo codice più pulito.

Modifica: versioni più recenti di Delphi consentono a una chiamata di uscire con un parametro che diventa il risultato della funzione (se è una funzione). Ciò potrebbe comportare in alcuni casi un codice più snello e (soggettivo) più pulito.

Esempio:

function IndexOfString(const Value: string; const StringArray: array of string): Integer;
begin
  for I:=Low(StringArray) to High(StringArray) do 
    if Value = StringArray[I] then 
      Exit(I);
  result := -1;
end;

Un altro approccio per questo sarebbe:

function IndexOfString(const Value: string; const StringArray: array of string): Integer;
begin
  result := -1;
  for I:=Low(StringArray) to High(StringArray) do 
    if Value = StringArray[I] then begin
      result := I;
      Break;
    end;
end;

Qualunque sia la migliore è più o meno una questione di gusti.

    
risposta data 19.05.2011 - 16:25
fonte
7

Domanda soggettiva. Io uso spesso Exit in un certo senso per verificare alcune condizioni iniziali e uscire presto se non vengono soddisfatte. Le mie funzioni spesso assomigliano a questo:

begin
  Result := ''; // default return value
  if (<input does not meet conditions>) then
    Exit;

  // continue to do something and return something useful
end;

Questo mi rende un po ' più leggibile per me. Ma cerco di non utilizzare Exit da vari punti nella stessa funzione.

    
risposta data 19.05.2011 - 16:38
fonte
7

Un'uscita anticipata come questa si chiama " clausola di salvaguardia ". Non è unico per Delphi. È sempre più considerato come buona pratica .

I vantaggi:

  • Meno righe di codice.
  • Se è + ve, renderlo più facile da capire.
  • Less nesting = più facile da capire.

Svantaggi:

  • Se il tuo metodo assegna risorse, è facile dimenticare di rilasciarle se non hai un singolo punto di uscita. Per questo motivo, questo stile di programmazione può essere più adatto a linguaggi gestiti come C #, ma può essere usato con Delphi se si è a conoscenza del problema.

Non sono convinto dagli argomenti che un metodo dovrebbe avere un singolo punto di uscita. Mi è stato suggerito che un ritorno anticipato è solo un altro tipo di GOTO. Tuttavia, il problema con GOTO è che può portarti ovunque, causando il pasticcio più orribile quando viene usato impropriamente. D'altra parte, un'uscita anticipata da un metodo sempre ti riporta al chiamante. Cosa potrebbe essere più ordinato di questo?

    
risposta data 19.05.2011 - 16:45
fonte
6

Personalmente, non credo ci sia bisogno di evitare l'uso di exit . È utile in funzioni come:

function IsDivideable(const A, B: Integer): Boolean;
begin
  Result := False;

  if (B = 0) then
     exit;

  Result := ((A mod B) = 0);
end;
    
risposta data 19.05.2011 - 16:31
fonte
2

A volte Exit potrebbe "rompere" la leggibilità del metodo. Un po 'come goto sarebbe (solo "meno male"). Io preferisco i blocchi condizionali, che rendono molto chiaro lo scopo di ogni pezzo di codice.

    
risposta data 19.05.2011 - 16:25
fonte
2

Cerco di non usare Exits nel codice. Se ti piace il codice fornito, allora preferirei cambiarlo per avere un pensiero più positivo in quanto generalmente scorre meglio:

  if Assigned(Staging.Current) then  
  begin   
    DoSomethingA(FileNameA);  
    DoSomethingB(FileNameB);  
    Staging.DeleteCurrent; 
  end;

C'è sempre più di un modo di fare qualcosa: il fattore decisivo è davvero l'implementazione più semplice da mantenere per te e il tuo team. Questo è in genere definito scrivendo più facilmente per leggere e capire il codice. Seppellire un'uscita nel bel mezzo di una procedura è in genere una cattiva implementazione, sul rovescio della medaglia avere un semplice codice di guardia one-liner sul fronte potrebbe cadere nel lato di facile lettura / comprensione per la maggior parte.

    
risposta data 19.05.2011 - 18:30
fonte
1

Concordo con gli altri poster che Exit nella mia vista riduce la leggibilità. Tuttavia, se lo si utilizzerà (e in alcune circostanze si migliora la leggibilità) la formattazione è molto importante. Vorrei cambiare il tuo sopra in

if Staging.Current = nil then exit

DoSomethingA(FileNameA);
DoSomethingB(FileNameB);
Staging.DeleteCurrent;

La riga aggiuntiva tra if e il resto delle istruzioni è importante.

    
risposta data 19.05.2011 - 16:29
fonte
1

Sto usando Exit quando ho una condizione complessa nel metodo, e dopo un po 'le specifiche cambiano ed è necessario aggiungere alcune nuove condizioni al codice, e costerebbe tempo per riorganizzare tutte le condizioni. Dipende da situazione a situazione.

Ma, se la logica è semplice, preferisco controllare le cose e finire il metodo se tutto va bene.

LE: un'altra discussione su questo Stile codice - Preferisci tornare da una funzione in anticipo o semplicemente utilizzare una dichiarazione IF?

    
risposta data 19.05.2011 - 16:57
fonte
-1

Non lo considererei buono o cattivo. Come tutte le risposte stanno mostrando, potrebbe difficilmente dipendere dal caso.

Personalmente mi piace la semplice "condizione di guardia" senza valore di ritorno, ma vorrei usarlo in una struttura funzionale complessa o con valori di ritorno di classe.

Forse alcune best practice potrebbero essere estratte dalle risposte sopra e potrebbero portare a una semplice lista di controllo, quando è sicuro e utile usare "Esci", e anche quando è meglio evitarlo.

    
risposta data 10.04.2013 - 16:42
fonte

Leggi altre domande sui tag