2012-05-23 13 views
11

Ho visto questo modello un paio di volte:Utilizzando infine, invece di cattura

 bool success = false; 
     try 
     { 
      DoSomething(); 
      success = true; 
     } 
     finally 
     { 
      if (!success) 
       Rollback(); 
     } 

E mi sono chiesto: perché questo è meglio che usare delle catture di rollback?

 try 
     { 
      DoSomething(); 
     } 
     catch 
     { 
      Rollback(); 
      throw; 
     } 

Quali sono le differenze tra i due modi per assicurarsi che le modifiche vengano ripristinate in caso di errore?

risposta

0

L'obiettivo chiaro qui è di chiamare Rollback in caso di errore. Entrambi i frammenti di codice raggiungono questo obiettivo. Il primo utilizza infine, che esegue sempre, che verifica che l'ultima riga del blocco try sia stata raggiunta correttamente. Il secondo rileva eventuali errori, ripristina la transazione e quindi rigenera l'eccezione che è stata rilevata. Il risultato di uno snippet è che eventuali eccezioni generate comporteranno un rollback mentre continuano a tornare al livello successivo.

Hai detto che il progetto è stato convertito da Java. In Java, è possibile re-throw an exception in modo simile a come è possibile in C# utilizzando throw;. Puoi anche throw a new exception che manterrà comunque lo stack di chiamate (et al). Il secondo è un po 'più chiaro/semplice in C# (non molto però) e il primo ha il vantaggio di lavorare effettivamente in Java come scritto.

+0

Questo ha senso. Non mi ero reso conto che Java non ti consentisse di replicare correttamente le excpetions. E qui stavo pensando che questo avrebbe avuto qualcosa a che fare con sezioni critiche e simili ... – configurator

+0

@configurator: Ora che ne parli, penso che potrebbe esserci una connessione a [Constrained Execution Regions] (http://msdn.microsoft.com/en-us/library/ms228973.aspx). – dtb

+4

-1 per "In Java non c'è modo di rilanciare un'eccezione" - [a parte 'throw e', ovvero] (http://stackoverflow.com/a/1097539/265143). –

1

finally viene sempre eseguito, non solo per rilevare eccezioni.

scontato, in questo specifico caso il rollback è necessaria solo quando c'è stato un errore, ma come un modello generale, il try-finally può essere più utile per la gestione delle risorse (dove spesso è necessario assicurarsi che avete sempre Close() o Dispose() di la tua risorsa correttamente). Soprattutto se l'autore del codice proviene da uno sfondo Java in cui questo idioma è più diffuso.

+2

Ma quando non ci sono eccezioni, "success" sarà falso, quindi la clausola finally è un no-op. – configurator

+0

@configurator, sì, vedere il mio aggiornamento. –

+0

Il commento in background Java ha senso dato il progetto in cui ho visto che questo è stato effettivamente portato da Java. – configurator

2

L'istruzione finally viene in genere utilizzata per la pulizia delle risorse. Il metodo Rollback() potrebbe essere utilizzabile lì se le eccezioni non sono gli unici motivi per ripristinare la transazione. I metodi Close() o Dispose() sono i primi candidati a finire nel blocco finale.

Tuttavia, non si desidera eseguire nulla che possa generare eccezioni.

+4

Questa risposta non ha molto a che fare con la domanda ... – configurator

+0

E 'semplicemente comune fare pulizia delle risorse nella dichiarazione finale, come ho detto. In questo modo non devi ricrearti. –

+0

@configurator è divertente, è il più votato finora, e ce ne sono altri simili, forse modifica la domanda per suscitare risposte più in linea con il tuo desiderio? –

4

Inserisco qui del codice anche se non è realmente correlato alla domanda (verrà eliminato in seguito).

Con questo programma:

using System; 

namespace testcs 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       try 
       { 
        foo(); 
        foo(); 
        foo(); 
       } 
       catch 
       { 
        throw; 
       } 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 

     private static void foo() 
     { 
      throw new Exception("oops"); 
     } 
    } 
} 

L'analisi dello stack (! Guardare i numeri di riga) è conservato, ma all'interno della funzione main vedrete "linea 19", la linea dove throw è invece il vero riga dove è stato chiamato foo() (riga 13).

+3

+1, punto preso, grazie per aver dedicato del tempo per creare il campione. Non penso che sia necessario eliminarlo, poiché illustra la differenza tra i due metodi nella domanda (ed è decisamente troppo lungo per un commento). – Heinzi

2

io non sono sicuro se questo non è solo anecdotal evidence, ma io personalmente ho usato questo modello per un motivo molto pratico: Quando DoSomething genera un'eccezione, il debugger di Visual Studio si romperà in DoSomething in cui si verifica l'eccezione nella prima versione, mentre si romperà allo throw; nella seconda versione. Ciò consente di ispezionare lo stato dell'applicazione prima che Rollback abbia eliminato tutto.

Screenshot

2

Se non si cura in questo particolare codice di ciò che tipo di eccezione si stanno recuperando l'uso:

try 
{ 
    DoSomething(); 
    ok = true; 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

Ciò manterrà Stack di chiamate nella sua forma originale per il 100%. Anche se si utilizza eccezione maching come questo:

try 
{ 
    DoSomething(); 
    ok = true; 
} 
catch(FirstExcetionType e1) 
{ 
    //do something 
} 
catch(SecondExcetionType e2) 
{ 
    //do something 
} 
catch(Exception e3) 
{ 
    //do something 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

usando finalmente alla fine può rendere il codice più leggibile che chiamare rollback da ogni dichiarazione singola cattura.

Problemi correlati