Il C # “finalmente” blocca SEMPRE eseguito?

Possibile duplicato:
Codificherò in un’istruzione Finally quando restituirò un valore in un blocco Try?

Considera il seguente codice C # codice. Esegue il blocco “finally”?

public void DoesThisExecute() { string ext = "xlsx"; string message = string.Empty; try { switch (ext) { case "xls": message = "Great choice!"; break; case "csv": message = "Better choice!"; break; case "exe": message = "Do not try to break me!"; break; default: message = "You will not win!"; return; } } catch (Exception) { // Handle an exception. } finally { MessageBox.Show(message); } } 

Ah, dopo aver finito di scrivere questo, mi sono reso conto che avrei potuto farlo io stesso in Visual Studio. Tuttavia, non esitate a rispondere!

No non lo fa. Verrà sempre eseguito a condizione che l’applicazione sia ancora in esecuzione (tranne durante un’eccezione FastFail , il collegamento MSDN , come notato da altri). Verrà eseguito quando esce dalla parte try / catch del blocco.

NON verrà eseguito se l’applicazione si arresta in modo anomalo: viene uccisa tramite un comando di kill process, ecc. Questo è molto importante, perché se si scrive codice che si aspetta assolutamente che venga eseguito, come se si eseguisse manualmente un rollback, e se non altrimenti saprà automaticamente commit, è ansible eseguire in uno scenario l’applicazione si interrompe prima che ciò accada. Onestamente, questo è uno scenario esterno, ma è importante prendere atto di queste situazioni.

Dalla specifica MSDN C # dell’istruzione try :

Le istruzioni di un blocco finally vengono sempre eseguite quando il controllo lascia una dichiarazione try . Questo è vero se il trasferimento del controllo avviene come risultato della normale esecuzione, come risultato dell’esecuzione di un’istruzione break , continue , goto o return , o come risultato della propagazione di un’eccezione dall’istruzione try .

fonte

Ci sono i casi in cui il blocco finally non verrà eseguito:

  1. Environment.FailFast
  2. Tipi di eccezione ineguibili
  3. Mancanza di corrente

Non è del tutto vero che alla finally sarà sempre eseguito. Vedi questa risposta di Haacked :

Due possibilità:

  • StackOverflowException
  • ExecutingEngineException

Il blocco finally non verrà eseguito quando c’è una StackOverflowException poiché non c’è spazio nello stack nemmeno per eseguire altro codice. Non verrà inoltre chiamato quando è presente un’eccezione ExecutingEngineException, che è molto rara.

In effetti, per qualsiasi tipo di eccezione asincrona (come StackOverflowException , OutOfMemoryException , ThreadAbortException ) l’esecuzione di un blocco finally non è garantita.

Tuttavia, queste eccezioni sono eccezioni di solito non è ansible ripristinare e, nella maggior parte dei casi, il processo verrà comunque chiuso.

In realtà, c’è anche almeno un altro caso in cui, finally non viene eseguito come descritto da Brian Rasmussen in una domanda ora cancellata :

L’altro caso di cui sono a conoscenza è se un finalizzatore genera un’eccezione. In tal caso, anche il processo viene immediatamente interrotto, pertanto la garanzia non viene applicata.

Il codice seguente illustra il problema

 static void Main(string[] args) { try { DisposableType d = new DisposableType(); d.Dispose(); d = null; GC.Collect(); GC.WaitForPendingFinalizers(); } catch { Console.WriteLine("catch"); } finally { Console.WriteLine("finally"); } } public class DisposableType : IDisposable { public void Dispose() { } ~DisposableType() { throw new NotImplementedException(); } } 

Un try / catch affidabile, infine, dovrà utilizzare le regioni di esecuzione vincasting (CER) . Un esempio è fornito da MSDN:

 [StructLayout(LayoutKind.Sequential)] struct MyStruct { public IntPtr m_outputHandle; } sealed class MySafeHandle : SafeHandle { // Called by P/Invoke when returning SafeHandles public MySafeHandle() : base(IntPtr.Zero, true) { } public MySafeHandle AllocateHandle() { // Allocate SafeHandle first to avoid failure later. MySafeHandle sh = new MySafeHandle(); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { MyStruct myStruct = new MyStruct(); NativeAllocateHandle(ref myStruct); sh.SetHandle(myStruct.m_outputHandle); } return sh; } } 

Un’ottima fonte di informazioni è il seguente articolo:

Best practice sull’affidabilità

Da MSDN try-finally (C # Reference)

Il blocco finally è utile per ripulire eventuali risorse allocate nel blocco try e per eseguire qualsiasi codice che deve essere eseguito anche in presenza di un’eccezione. Il controllo viene sempre passato al blocco finally indipendentemente da come il blocco try si chiude .

Il blocco finale verrà eseguito, proprio tra queste righe:

 message = "You will not win!"; return; 

Sì, finally esegue sempre, ora se il codice nel blocco finally causerà o meno un’eccezione è una storia diversa.

La risposta giusta è Sì.

Prova a eseguire il debug del tuo programma e inserisci un punto di interruzione e guarda come il controllo colpisce ancora il blocco finale.

No, non lo è.

C’è solo un modo per aggirarlo e questo è Environment.FailFast() . Vedi http://msdn.microsoft.com/de-de/library/ms131100.aspx . In ogni altro caso è garantito che i finalizzatori vengano eseguiti 😉

Il metodo FailFast scrive la stringa del messaggio nel registro eventi dell’applicazione Windows, crea un dump dell’applicazione e quindi termina il processo corrente. La stringa di messaggi è inclusa anche nella segnalazione degli errori a Microsoft.

Utilizzare il metodo FailFast invece del metodo Exit per terminare l’applicazione se lo stato dell’applicazione è danneggiato irreparabilmente e l’esecuzione dei blocchi try / finally e finalizzatori dell’applicazione corrompe le risorse del programma.

Sì, in circostanze normali (come molti altri hanno sottolineato).

Il blocco finally è utile per ripulire eventuali risorse allocate nel blocco try e per eseguire qualsiasi codice che deve essere eseguito anche in presenza di un’eccezione. Il controllo viene sempre passato al blocco finally indipendentemente da come il blocco try si chiude.

Mentre catch è usato per gestire le eccezioni che si verificano in un blocco di istruzioni, viene infine utilizzato per garantire che un blocco di istruzioni di codice venga eseguito indipendentemente da come il blocco di prova precedente viene chiuso.

http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx

Risposta semplice Sì. Ma ci sono alcune “eccezioni” alla regola.