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

Sto rivedendo del codice per un amico e dico che stava usando una dichiarazione di ritorno all’interno di un blocco try-finally. Il codice nella sezione Finally continua a sparare anche se il resto del blocco try non lo fa?

Esempio:

public bool someMethod() { try { return true; throw new Exception("test"); // doesn't seem to get executed } finally { //code in question } } 

    Risposta semplice: sì.

    Normalmente sì La sezione finale è garantita per eseguire qualsiasi cosa accada comprese eccezioni o dichiarazioni di reso. Un’eccezione a questa regola è un’eccezione asincrona che si verifica nel thread ( OutOfMemoryException , StackOverflowException ).

    Per ulteriori informazioni sulle eccezioni asincrone e sul codice affidabile in tali situazioni, leggere le aree di esecuzione vincolate .

    Ecco un piccolo test:

     class Class1 { [STAThread] static void Main(string[] args) { Console.WriteLine("before"); Console.WriteLine(test()); Console.WriteLine("after"); } static string test() { try { return "return"; } finally { Console.WriteLine("finally"); } } } 

    Il risultato è:

     before finally return after 

    Citando da MSDN

    infine viene utilizzato per garantire che un blocco di istruzioni del codice venga eseguito indipendentemente da come il blocco try precedente viene chiuso .

    Generalmente sì, alla fine funzionerà.

    Per i seguenti tre scenari, il test verrà eseguito SEMPRE :

    1. Non si verificano eccezioni
    2. Eccezioni sincrone (eccezioni che si verificano nel normale stream del programma).
      Ciò include le eccezioni compatibili con CLS derivanti dalle eccezioni compatibili con System.Exception e non CLS, che non derivano da System.Exception. Le eccezioni conformi a CLS vengono automaticamente integrate da RuntimeWrappedException. C # non può lanciare eccezioni di reclami non CLS, ma linguaggi come C ++. C # potrebbe chiamare in codice scritto in una lingua che può generare eccezioni compatibili con CLS.
    3. ThreadAbortException asincrona
      A partire da .NET 2.0, un ThreadAbortException non impedirà più l’esecuzione definitiva. ThreadAbortException è ora issato prima o dopo l’ultimo. Alla fine verrà sempre eseguito e non verrà interrotto da un’interruzione del thread, a condizione che la prova sia stata effettivamente inserita prima che si verificasse l’interruzione del thread.

    Lo scenario seguente, alla fine non verrà eseguito:

    StackOverflowException asincrona.
    A partire da .NET 2.0, un overflow dello stack causerà la fine del processo. Alla fine non verrà eseguito, a meno che non venga applicato un ulteriore vincolo per rendere finalmente un CER (Regione di esecuzione vincasting). I CER non dovrebbero essere utilizzati nel codice utente generale. Dovrebbero essere usati solo dove è fondamentale che il codice di pulizia venga sempre eseguito, dopo che tutto il processo si sta arrestando comunque sull’overflow dello stack e tutti gli oggetti gestiti verranno quindi ripuliti per impostazione predefinita. Pertanto, l’unico posto che un CER dovrebbe essere rilevante è per le risorse che vengono allocate al di fuori del processo, ad esempio, handle non gestiti.

    In genere, il codice non gestito viene inserito da alcune classi gestite prima di essere utilizzato dal codice utente. La class wrapper gestita utilizzerà in genere SafeHandle per racchiudere l’handle non gestito. SafeHandle implementa un finalizzatore critico e un metodo Release che viene eseguito in un CER per garantire l’esecuzione del codice di pulizia. Per questo motivo, non dovresti vedere il CER con il codice utente nascosto.

    Quindi il fatto che finalmente non venga eseguito su StackOverflowException non dovrebbe avere alcun effetto sul codice utente, poiché il processo terminerà comunque. Se si dispone di un caso limite in cui è necessario pulire alcune risorse non gestite, al di fuori di SafeHandle o CriticalFinalizerObject, utilizzare un CER come segue; ma per favore nota, questa è una ctriggers pratica – il concetto non gestito dovrebbe essere astratto per una class gestita e appropriato SafeHandle (s) di design.

    per esempio,

     // No code can appear after this line, before the try RuntimeHelpers.PrepareConstrainedRegions(); try { // This is *NOT* a CER } finally { // This is a CER; guaranteed to run, if the try was entered, // even if a StackOverflowException occurs. } 

    C’è un’eccezione molto importante a questa che non ho visto menzionata in altre risposte, e che (dopo aver programmato in C # per 18 anni) non posso credere di non saperlo.

    Se lanciate o triggerste un’eccezione di qualsiasi tipo all’interno del blocco catch (non solo strane StackOverflowExceptions e cose simili), e non avete l’intero blocco try/catch/finally all’interno di un altro blocco try/catch , il vostro blocco finale non verrà eseguito. Questo è facilmente dimostrato – e se non l’avessi visto da me, data la frequenza con cui ho letto che sono solo strane, minuscole casse d’angolo che possono far sì che un blocco finale non venga eseguito, non ci avrei creduto.

     static void Main(string[] args) { Console.WriteLine("Beginning demo of how finally clause doesn't get executed"); try { Console.WriteLine("Inside try but before exception."); throw new Exception("Exception #1"); } catch (Exception ex) { Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception)."); throw; } finally { Console.WriteLine("This never gets executed, and that seems very, very wrong."); } Console.WriteLine("This never gets executed, but I wasn't expecting it to."); Console.ReadLine(); } 

    Sono sicuro che c’è una ragione per questo, ma è bizzarro che non sia più conosciuto. ( Qui è annotato , ad esempio, ma non in questa particolare domanda).

    Mi rendo conto che sono in ritardo per la festa ma nello scenario (diverso dall’esempio dell’OP) dove effettivamente viene generata un’eccezione negli stati MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): “Se l’eccezione non viene rilevata, l’esecuzione del blocco finally dipende dal fatto che il sistema operativo scelga di triggersre un’operazione di svolgimento delle eccezioni.”

    Il blocco finally è garantito solo se alcune altre funzioni (come Main) più avanti lo stack di chiamate intercetta l’eccezione. Questo dettaglio di solito non è un problema perché tutti i programmi C # degli ambienti run-time (CLR e OS) girano sulla maggior parte delle risorse che un processo possiede quando esce (handle di file, ecc.). In alcuni casi, tuttavia, potrebbe essere cruciale: un’operazione di database a metà strada che si desidera eseguire il commit. rilassarsi; o una connessione remota che potrebbe non essere chiusa automaticamente dal sistema operativo e quindi bloccare un server.

    Sì. Questo è in effetti il ​​punto principale di una dichiarazione finale. A meno che non si verifichi qualcosa di catestropico (esaurimento della memoria, computer scollegato, ecc.) L’istruzione finale dovrebbe sempre essere eseguita.

    infine non verrà eseguito nel caso in cui si stia uscendo dall’applicazione utilizzando System.exit (0); come in

     try { System.out.println("try"); System.exit(0); } finally { System.out.println("finally"); } 

    il risultato sarebbe solo: prova

    Inoltre, non si triggers l’eccezione non rilevata e viene eseguita in un thread ospitato in un servizio di Windows

    Infine non viene eseguito quando si trova in una discussione in esecuzione in un servizio di Windows

    Il 99% degli scenari sarà garantito che il codice all’interno del blocco finally verrà eseguito, tuttavia, pensa a questo scenario: hai un thread che ha un try -> finally block (no catch ) e ottieni un’eccezione non gestita all’interno di quel filo. In questo caso, il thread uscirà e il blocco finally non verrà eseguito (l’applicazione può continuare a essere eseguita in questo caso)

    Questo scenario è piuttosto raro, ma è solo per dimostrare che la risposta non è SEMPRE “Sì”, è la maggior parte delle volte “Sì” ea volte, in rare condizioni, “No”.

    Lo scopo principale del blocco finale è eseguire qualsiasi cosa sia scritta al suo interno. Non dovrebbe dipendere da ciò che accade nel tentativo o nella cattura. Tuttavia con System.Environment.Exit (1) l’applicazione uscirà senza passare alla riga successiva del codice.