Domanda

In alcuni codici Delphi 7 che sto conservando, ho notato molte delle seguenti situazioni:

with ADOQuery1 do begin
  // .. fill out sql.text, etc
  try
    execSQL;
  except
    raise;
  end;
end;

Mi sembra che questi blocchi di prova possano essere rimossi, poiché non fanno nulla. Tuttavia, sono diffidente nei confronti di possibili effetti collaterali sottili.

Qualcuno può pensare a casi in cui questi blocchi potrebbero effettivamente fare qualcosa che non accadrebbe senza di loro lì?

È stato utile?

Soluzione

In questo contesto, l'operazione di rilancio non ha alcun effetto e dovrebbe essere rimossa perché sta semplicemente rilanciando l'eccezione che il blocco di eccezioni ha appena rilevato. in genere viene utilizzato per trasferire il controllo alla fine del blocco quando non è disponibile una gestione degli errori appropriata. Di seguito gestiamo l'eccezione personalizzata, ma qualsiasi altra eccezione dovrebbe essere gestita altrove.

try
  someOperation;
except
  on e: ECustomException do
    SomeCustomHandelr;
  else
     begin
       // the raise is only useful to rethrow the exception to an encompasing 
       // handler.  In this case after I have called my logger code. as Rob
       // mentioned this can be omitted if you arent handling anything because
       // the compiler will simply jump you to the next block if there is no
       // else.
       LogUnexpectedException('some operation failed',e);
       raise;
     end;
end;

Fai attenzione che esista una forma simile senza il "rialzo" che ha l'effetto collaterale di mangiare / nascondere eventuali eccezioni. pratiche di sviluppatori senza scrupoli che si spera siano passati a posizioni con la concorrenza.

with ADOQuery1 do begin  
  // .. fill out sql.text, etc  
  try    
    execSQL; 
  except
    // no handler so this just eats any "errors"    
  end;

Altri suggerimenti

La rimozione del codice tranne nello snippet di codice sopra riportato non farà alcuna differenza. Puoi (e credo che dovresti poiché riduce la leggibilità) rimuoverlo.

Okay, davvero due domande qui.

Innanzitutto, è significativo: se execSQL genera un'eccezione, viene catturato dal blocco try e inoltrato all'eccezione. Quindi viene inoltrato dal rilancio al blocco superiore successivo.

Secondo, è utile ? Probabilmente no. Quasi certamente è il risultato di una di queste tre cose:

  1. Qualcuno con i capelli a punta ha scritto uno standard di codifica secondo il quale "tutte le operazioni che possono generare un'eccezione devono trovarsi in un blocco try."
  2. Qualcuno voleva tornare e trasformare le eccezioni fatte dalla dichiarazione execSQL in qualche altra eccezione più significativa.
  3. Qualcuno di nuovo non era a conoscenza del fatto che ciò che avevano scritto fosse isomorfo nel lasciare che l'ambiente totale si preoccupasse dell'eccezione, e quindi ha pensato che devono inoltrarlo.

Potrei aver risposto un po 'in fretta, vedi alla fine ...
Come è, è inutile per l'applicazione .
Periodo!

Ora sul " perché " lato. Potrebbe essere standardizzare la gestione delle eccezioni se c'era / era / sarà / è in altri luoghi / qualche tipo di codice di registrazione inserito prima del rilancio:

  try
    execSQL;
  except
    // Log Exception..
    on E: Exception do
    begin
      LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message]));
      raise;
    end;
  end;

o per il codice di pulizia:

  try
    execSQL;
  except
    //some FreeAndNil..
    raise;
  end;

Aggiorna : ci sarebbe 1 caso in cui vedrei un uso proprio come è ...
... per poter mettere un Breakpoint sulla linea raise , per avere la possibilità di vedere cosa sta succedendo nel contesto di quel blocco di codice.

Questo codice non fa altro che consentire al programmatore originale di posizionare un punto di interruzione su "Solleva" e di vedere l'eccezione più vicina nell'origine alla sua possibile causa. In questo senso è una tecnica di debug perfettamente ragionevole.

In realtà, dovrei postarlo come commento alle risposte di François, ma non so è possibile inserire lì un codice formattato :( Quindi sto pubblicando questo come risposta.

2mghie:

  
    
      

Il secondo è completamente unidiomatico, si userebbe invece finalmente.

    
  

No, "finalmente". pulirà sempre l'oggetto. & Quot; Tranne " - solo su eccezione. Considera il caso della funzione, che crea, riempie e restituisce un oggetto:

function CreateObj: TSomeObj;
begin
  Result := TSomeObj.Create;
  try
    ... // do something with Result: load data, fill props, etc.
  except
    FreeAndNil(Result); // oops: bad things happened. Free object to avoid leak.
    raise;
  end;
end;

Se inserisci " infine " lì - la funzione restituirà sempre zero. Se ometti " prova " blocca affatto - ci saranno perdite di risorse in caso di eccezione in " ... " ;.

P.S. Ovviamente, puoi utilizzare " infine " e controlla ExceptObj, ma ... non è brutto?

Il titolo contiene una domanda piuttosto ampia, mentre la sua spiegazione fornisce un esempio più specifico. Quindi, la mia risposta alla domanda come procede dall'esempio, può senza dubbio aggiungere qualcosa di utile a ciò che è già stato detto qui.

Ma forse Blorgbeard vuole davvero sapere se è affatto significativo provare ... tranne rilancio; fine . In Delphi 7, se ricordo correttamente, Exit attiverebbe la parte finally di un blocco try-finally (come se fosse una specie di eccezione). Qualcuno potrebbe considerare tale comportamento inappropriato per il proprio compito e l'utilizzo della costruzione in questione è piuttosto una soluzione alternativa.

Solo sarebbe ancora strano usare un singolo rilancio; lì, ma poi avremmo dovuto parlare di utilità piuttosto che significatività , come Charlie ha ben osservato.

Questo codice non fa nulla se non il rilanciare un'eccezione che sarà già sollevata senza questo tentativo tranne il blocco. Puoi rimuoverlo in sicurezza.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top