it-swarm.com.de

Wird der Code in einer finally-Anweisung ausgelöst, wenn ich einen Wert in einem Try-Block zurückgeben?

Ich überprüfe einen Code für einen Freund und sage, dass er eine return-Anweisung innerhalb eines try-finally-Blocks verwendet hat. Wird der Code im Abschnitt Schließlich immer noch ausgelöst, obwohl der Rest des try-Blocks nicht funktioniert?

Beispiel:

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

Einfache antwort: ja.

241
Andrew Rollings

Normalerweise ja. Der finally-Abschnitt führt garantiert aus, was auch immer geschieht, einschließlich Ausnahmen oder return-Anweisungen. Eine Ausnahme von dieser Regel ist eine asynchrone Ausnahme im Thread (OutOfMemoryException, StackOverflowException).

Um mehr über asynchrone Ausnahmen und zuverlässigen Code in diesen Situationen zu erfahren, lesen Sie den Abschnitt über eingeschränkte Ausführungsbereiche .

194
Mehrdad Afshari

Hier ist ein kleiner 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");
        }
    }
}

Das Ergebnis ist:

before
finally
return
after
139
Jon B

Zitieren aus MSDN 

finally wird verwendet, um die Ausführung eines Anweisungsblocks zu gewährleisten, unabhängig davon, wie der vorherige try - Block beendet ist.

33
Perpetualcoder

Generell ja, das wird endlich laufen.

Für die folgenden drei Szenarien wird das IMMER schließlich ausgeführt:

  1. Es gibt keine Ausnahmen
  2. Synchrone Ausnahmen (Ausnahmen, die im normalen Programmablauf auftreten).
    Dies schließt CLS-kompatible Ausnahmen ein, die von System.Exception und nicht-CLS-kompatiblen Ausnahmen abgeleitet sind und nicht von System.Exception abgeleitet sind. Nicht mit CLS kompatible Ausnahmen werden automatisch von der RuntimeWrappedException umschlossen. C # kann keine Ausnahmen für Nicht-CLS-Beschwerden auslösen, aber Sprachen wie C++ können dies. C # könnte in Code aufgerufen werden, der in einer Sprache geschrieben ist, die nicht CLS-konforme Ausnahmen auslösen kann.
  3. Asynchroner ThreadAbortException
    Ab .NET 2.0 verhindert eine ThreadAbortException die Ausführung von final nicht mehr. ThreadAbortException wird jetzt vor oder nach dem final angehoben. Der finally wird immer ausgeführt und wird nicht durch einen Thread-Abbruch unterbrochen, solange der Versuch tatsächlich vor dem Thread-Abbruch eingegeben wurde.

Das folgende Szenario wird schließlich nicht ausgeführt:

Asynchrone StackOverflowException.
Ab .NET 2.0 führt ein Stapelüberlauf dazu, dass der Prozess beendet wird. Das final wird nicht ausgeführt, es sei denn, es wird eine weitere Einschränkung angewendet, um aus dem endgültigen CER (Constrained Execution Region) einen CER (Constrained Execution Region) zu machen. CERs sollten nicht im allgemeinen Benutzercode verwendet werden. Sie sollten nur verwendet werden, wenn es wichtig ist, dass Bereinigungscode immer ausgeführt wird - nachdem der Prozess ohnehin bei einem Stapelüberlauf heruntergefahren wurde und alle verwalteten Objekte daher standardmäßig bereinigt werden. Die einzige Stelle, an der eine CER relevant sein sollte, sind Ressourcen, die außerhalb des Prozesses zugewiesen werden, z. B. nicht verwaltete Handles.

Normalerweise wird nicht verwalteter Code von einer verwalteten Klasse eingeschlossen, bevor er vom Benutzercode verbraucht wird. Die verwaltete Wrapper-Klasse verwendet normalerweise ein SafeHandle, um den nicht verwalteten Handle einzuwickeln. Das SafeHandle implementiert einen kritischen Finalizer und eine Release-Methode, die in einer CER ausgeführt wird, um die Ausführung des Bereinigungscodes zu gewährleisten. Aus diesem Grund sollten Sie nicht sehen, dass der CER durch den gesamten Benutzercode verstreut ist.

Die Tatsache, dass das schließlich nicht für StackOverflowException ausgeführt wird, sollte sich daher nicht auf Benutzercode auswirken, da der Prozess trotzdem beendet wird. Wenn Sie einen Edge-Fall haben, in dem Sie eine nicht verwaltete Ressource außerhalb eines SafeHandle- oder CriticalFinalizerObject-Objekts bereinigen müssen, verwenden Sie eine CER wie folgt. Beachten Sie jedoch, dass dies eine schlechte Praxis ist - das nicht verwaltete Konzept sollte von einer verwalteten Klasse (n) und entsprechenden SafeHandle (s) abstrahiert werden.

z.B.,

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

Es gibt eine sehr wichtige Ausnahme, die ich in keiner anderen Antwort erwähnt habe, und die (nachdem ich 18 Jahre in C # programmiert hatte) nicht glauben kann, dass ich es nicht wusste.

Wenn Sie eine Ausnahme von any sort innerhalb Ihres catch-Blocks auslösen oder auslösen (nicht nur seltsame StackOverflowExceptions und Dinge dieses Typs), und Sie nicht den gesamten try/catch/finally-Block in einem anderen try/catch-Block haben, wird Ihr finally-Block gewonnen. t ausführen. Dies ist leicht zu beweisen - und wenn ich es selbst nicht gesehen hätte, so oft ich gelesen habe, dass es nur wirklich seltsame, winzige Eckfälle sind, die dazu führen können, dass ein finally-Block nicht ausgeführt wird, hätte ich es nicht geglaubt.

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();
}

Ich bin sicher, dass es einen Grund dafür gibt, aber es ist bizarr, dass er nicht weiter bekannt ist. (Es ist zum Beispiel hier notiert, aber an keiner Stelle in dieser speziellen Frage.

9
Ken Smith

Ich erkenne, dass ich zu spät zur Party komme, aber in dem Szenario (das sich vom OP-Beispiel unterscheidet), in dem tatsächlich eine Ausnahme von MSDN ausgelöst wird ( https://msdn.Microsoft.com/en-us/library/zwc8s4fz.aspx) ): "Wenn die Ausnahme nicht abgefangen wird, hängt die Ausführung des finally-Blocks davon ab, ob das Betriebssystem einen Ausnahme-Abwicklungsvorgang auslöst." 

Der finally-Block kann nur Guaranteed ausgeführt werden, wenn eine andere Funktion (z. B. Main) im Call Stack die Ausnahme fängt. Dieses Detail ist normalerweise kein Problem, da alle Laufzeitumgebungen (CLR und OS) C # -Programme auf den meisten Ressourcen laufen, die ein Prozess besitzt, wenn er beendet wird (Dateihandles usw.). In einigen Fällen kann es jedoch von entscheidender Bedeutung sein: Eine Datenbankoperation, die zur Hälfte ausgeführt wird und die Sie festschreiben möchten. abwickeln; oder eine Remote-Verbindung, die möglicherweise nicht automatisch vom Betriebssystem geschlossen wird und dann einen Server blockiert. 

6

Ja. Das ist in der Tat der Hauptpunkt einer abschließenden Aussage. Wenn nicht eine Katastrophe auftritt (nicht genügend Speicher, Computer nicht angeschlossen usw.), sollte die finally-Anweisung immer ausgeführt werden.

3

Es wird auch nicht bei nicht erfassten Ausnahmen ausgelöst und in einem Thread ausgeführt, der in einem Windows-Dienst gehostet wird

Wird schließlich nicht ausgeführt, wenn in einem Thread ein Windows-Dienst ausgeführt wird

2
Stig

wird schließlich nicht ausgeführt, wenn Sie die Anwendung mit System.exit (0) beenden; wie in

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

das Ergebnis wäre nur: try

2
Hakuna Matata

Ja Endlich anrufen.

  public static bool someMethod()
    {
        try
        {

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

Bei 99% der Szenarien wird garantiert, dass der Code im finally-Block ausgeführt wird. Denken Sie jedoch an folgendes Szenario: Sie haben einen Thread, der über einen try-> finally-Block (keine catch) verfügt, und Sie erhalten eine unbehandelte Ausnahme Faden. In diesem Fall wird der Thread beendet und der finally-Block wird nicht ausgeführt (die Anwendung kann in diesem Fall weiter ausgeführt werden).

Dieses Szenario ist ziemlich selten, aber es zeigt nur, dass die Antwort IMMER nicht "Ja" ist, sondern meistens "Ja" und manchmal, in seltenen Fällen, "Nein".

0
Jonathan Perry

Der Hauptzweck von finally-Block ist die Ausführung dessen, was in ihm geschrieben ist. Es sollte nicht davon abhängen, was in try oder catch geschieht. Wie auch immer, mit System.Environment.Exit (1) wird die Anwendung beendet, ohne zur nächsten Codezeile zu wechseln.

0
Ashish Sahu