Domanda

Sto rivedendo un codice per un amico e dico che stava usando un'istruzione return all'interno di un blocco try-finally. Il codice nella sezione Finalmente continua a funzionare anche se il resto del blocco try no?

Esempio:

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

Soluzione

Risposta semplice: Sì.

Altri suggerimenti

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

Per ulteriori informazioni sulle eccezioni asincrone e sul codice affidabile in tali situazioni, leggi regioni 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

Citazione da MSDN

  

infine viene utilizzato per garantire l'esecuzione di un blocco di istruzioni del codice indipendentemente da come è uscito il precedente blocco prova uscito .

Generalmente sì, finalmente verrà eseguito.

Per i seguenti tre scenari, infine SEMPRE verrà eseguito:

  1. Non si verificano eccezioni
  2. Eccezioni sincrone (eccezioni che si verificano nel normale flusso del programma).
    Ciò include le eccezioni conformi a CLS che derivano da System.Exception e le eccezioni non conformi a CLS, che non derivano da System.Exception. Le eccezioni non conformi a CLS vengono automaticamente racchiuse da RuntimeWrappedException. C # non può generare eccezioni di reclamo non CLS, ma possono farlo linguaggi come C ++. C # potrebbe chiamare il codice scritto in una lingua che può generare eccezioni non conformi a CLS.
  3. Asincrono ThreadAbortException
    A partire da .NET 2.0, una ThreadAbortException non impedirà più l'esecuzione di. ThreadAbortException è ora sollevato prima o dopo il fine. L'elaborazione finale verrà sempre eseguita e non verrà interrotta da un'interruzione del thread, purché il tentativo sia stato effettivamente inserito prima dell'interruzione del thread.

Il seguente scenario, finalmente non verrà eseguito:

StackOverflowException asincrono.
A partire da .NET 2.0 un overflow dello stack causerà la chiusura del processo. L'ultimo non verrà eseguito, a meno che non venga applicato un ulteriore vincolo per rendere finalmente un CER (Constrained Execution Region). I CER non devono essere utilizzati nel codice utente generale. Dovrebbero essere usati solo laddove è fondamentale che il codice di pulizia venga sempre eseguito, dopo che tutto il processo viene comunque arrestato in caso di overflow dello stack e tutti gli oggetti gestiti verranno quindi ripuliti per impostazione predefinita. Pertanto, l'unico posto in cui una CER dovrebbe essere pertinente è per le risorse che sono allocate al di fuori del processo, ad esempio handle non gestiti.

In genere, il codice non gestito viene racchiuso da alcune classi gestite prima di essere utilizzato dal codice utente. La classe wrapper gestita in genere utilizzerà SafeHandle per eseguire il wrapping dell'handle non gestito. SafeHandle implementa un finalizzatore critico e un metodo di rilascio che viene eseguito in un CER per garantire l'esecuzione del codice di pulizia. Per questo motivo, non dovresti vedere CERs disseminati in tutto il codice utente.

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 ripulire alcune risorse non gestite, al di fuori di SafeHandle o CriticalFinalizerObject, utilizzare un CER come segue; ma tieni presente che si tratta di una cattiva pratica: il concetto non gestito dovrebbe essere estratto in classi gestite e SafeHandle appropriati in base alla progettazione.

per es.,

// 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.
}

Esiste un'eccezione molto importante a ciò che non ho visto menzionato in altre risposte e che (dopo aver programmato in C # per 18 anni) non riesco a credere di non saperlo.

Se lanci o attivi un'eccezione di qualsiasi ordinamento all'interno del tuo blocco catch (non solo strani StackOverflowExceptions e cose del genere), e non hai l'intero blocco try / catch / finally all'interno di un altro blocco try / catch , il tuo blocco finalmente non verrà eseguito. Questo è facilmente dimostrato - e se non lo avessi visto da solo, data la frequenza con cui ho letto che sono solo dei casi angolari davvero strani, che possono far sì che un blocco finalmente non venga eseguito, io 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(<*>quot;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 è strano che non sia più conosciuto. (Si noti qui per esempio, ma non in nessun punto di questa particolare domanda.)

Mi rendo conto di essere in ritardo per la festa, ma nello scenario (diverso dall'esempio del PO) in cui 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 attivare un'operazione di svolgimento dell'eccezione. "

L'esecuzione del blocco finally è solo garantita se qualche altra funzione (come Main) più in alto nello stack di chiamate rileva l'eccezione. Questo dettaglio di solito non è un problema perché tutti i programmi C # degli ambienti di runtime (CLR e OS) vengono eseguiti sulla maggior parte delle risorse libere che un processo possiede quando esce (handle di file, ecc.). In alcuni casi può essere cruciale: un'operazione di database a metà in corso che si desidera impegnare resp. rilassarsi; o qualche connessione remota che potrebbe non essere chiusa automaticamente dal sistema operativo e quindi bloccare un server.

Sì. Questo è in effetti quel punto principale di un'affermazione infine. A meno che non si verifichi qualcosa di catastrofico (memoria insufficiente, computer scollegato, ecc.), L'istruzione finally deve sempre essere eseguita.

Inoltre non si attiverà su eccezioni non rilevate e in esecuzione in un thread ospitato in un servizio di Windows

Infine non viene eseguito quando in Discussione in esecuzione in un servizio di Windows

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: provare

99% degli scenari sarà garantito che il codice all'interno del blocco finalmente verrà eseguito, tuttavia, pensa a questo scenario: hai un thread che ha un prova - > infine blocco (nessun catch ) e ottieni un'eccezione non gestita all'interno di quel thread. In questo caso, il thread verrà chiuso e il suo blocco infine non verrà eseguito (l'applicazione può continuare a funzionare in questo caso)

Questo scenario è piuttosto raro, ma è solo per dimostrare che la risposta non è SEMPRE " Sì " ;, è la maggior parte delle volte " Sì " e talvolta, in rare condizioni, "No".

Lo scopo principale di finally block è quello di eseguire tutto ciò che è scritto al suo interno. Non dovrebbe dipendere da qualsiasi cosa accada in try o catch. Tuttavia, con System.Environment.Exit (1) l'applicazione verrà chiusa senza passare alla riga di codice successiva.

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