Warum endlich in C # verwenden?

187

Was auch immer sich in den endgültigen Blöcken befindet, wird (fast) immer ausgeführt. Was ist also der Unterschied zwischen dem Einschließen von Code oder dem Nicht-Schließen von Code?

Rodrigo
quelle
3
Was meinst du damit, es nicht geschlossen zu lassen?
Ramesh
5
Und was meinst du mit "(fast)"?
Beska
49
Wenn Sie das Netzkabel herausziehen, während ein Computer eine try-Klausel ausführt, wird die finally-Klausel nicht aufgerufen.
Dour High Arch
5
lol, ja, das stimmt, aber dafür kannst du nicht wirklich programmieren, oder?
Ed S.
2
@Ed: Verwenden Sie Transaktionen. Ihre try-Klausel muss eine Art temporäre oder speicherinterne Änderung vornehmen, die in einer einzelnen atomaren Änderung in der finally-Klausel beibehalten werden kann. Dies ist selten einfach und erfordert möglicherweise spezielle Hardware.
Dour High Arch

Antworten:

403

Der Code in einem finally-Block wird ausgeführt, unabhängig davon, ob eine Ausnahme vorliegt oder nicht. Dies ist sehr praktisch, wenn es um bestimmte Reinigungsfunktionen geht, die Sie immer wie das Schließen von Verbindungen ausführen müssen.

Ich vermute, Ihre Frage ist, warum Sie dies tun sollten:

try
{
    doSomething();
}
catch
{
    catchSomething();
}
finally
{
    alwaysDoThis();
}

Wenn Sie dies tun können:

try
{
    doSomething();
}
catch
{
    catchSomething();
}

alwaysDoThis();

Die Antwort ist, dass der Code in Ihrer catch-Anweisung häufig entweder eine Ausnahme erneut auslöst oder aus der aktuellen Funktion ausbricht. Mit dem letzteren Code wird "alwaysDoThis ();" Der Aufruf wird nicht ausgeführt, wenn der Code in der catch-Anweisung eine Rückgabe ausgibt oder eine neue Ausnahme auslöst.

Kevin Pang
quelle
3
Hmm. Sehr ähnlich zu dem, was ich gesagt habe, aber klarer und genauer. Definitiv +1.
Beska
45
Dies gilt auch für "return" innerhalb des try {} -Blocks.
Lucas
4
Tatsächlich gilt es auch ohne einen catch {} -Block (versuchen Sie es einfach / endlich und lassen Sie Ausnahmen aufsteigen)
Lucas
besser als meins, war auf der Arbeit und wollte nicht zehn Minuten damit verbringen, es im Detail zu beantworten. +1
Matt Briggs
2
Ja, genau das hatte ich vor: D Jetzt verstehe ich es.
Rodrigo
62

Die meisten Vorteile der Verwendung von try-finally wurden bereits hervorgehoben, aber ich dachte, ich würde diesen hinzufügen:

try
{
    // Code here that might throw an exception...

    if (arbitraryCondition)
    {
        return true;
    }

    // Code here that might throw an exception...
}
finally
{
    // Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}

Dieses Verhalten macht es in verschiedenen Situationen sehr nützlich, insbesondere wenn Sie eine Bereinigung durchführen (Ressourcen entsorgen) müssen, obwohl ein using- Block in diesem Fall häufig besser ist.

Noldorin
quelle
2
Dies ist buchstäblich der einzige Grund, den ich endlich benutze
Christopher Townsend
12

Jedes Mal, wenn Sie nicht verwaltete Codeanforderungen wie Stream-Reader, Datenbankanforderungen usw. verwenden. und wenn Sie die Ausnahme abfangen möchten, verwenden Sie try catch finally und schließen Sie den Stream, den Datenleser usw. im finally. Wenn Sie dies nicht tun, wenn die Fehler nicht geschlossen werden, ist dies bei Datenbankanforderungen wirklich schlecht

 SqlConnection myConn = new SqlConnection("Connectionstring");
        try
        {
            myConn.Open();
            //make na DB Request                
        }
        catch (Exception DBException)
        {
            //do somehting with exception
        }
        finally
        {
           myConn.Close();
           myConn.Dispose();
        }

Wenn Sie den Fehler nicht abfangen möchten, verwenden Sie

 using (SqlConnection myConn = new SqlConnection("Connectionstring"))
        {
            myConn.Open();
            //make na DB Request
            myConn.Close();
        }

und das Verbindungsobjekt wird automatisch entsorgt, wenn ein Fehler auftritt, Sie den Fehler jedoch nicht erfassen

Bob der Hausmeister
quelle
2
Dispose () schließt auch die Verbindung (), ohne dass beide aufgerufen werden müssen. Close () taucht NICHT ein (), Sie können die Verbindung wieder öffnen.
Lucas
Schön, danke, dass du die Verwendung erwähnt hast. Sonst müsste ich antworten.
Dan Rosenstark
10

Denn schließlich wird ausgeführt, auch wenn Sie keine Ausnahme in einem catch-Block behandeln.

Matt Briggs
quelle
7

Schließlich können Anweisungen auch nach der Rückkehr ausgeführt werden.

private int myfun()
{
    int a = 100; //any number
    int b = 0;
    try
    {
        a = (5 / b);
        return a;
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
        return a;
    }

 //   Response.Write("Statement after return before finally");  -->this will give error "Syntax error, 'try' expected"
    finally
    {
      Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
    } 

    Response.Write("Statement after return after finally");  // -->Unreachable code
}
Prateek Gupta
quelle
7

finally, wie in:

try {
  // do something risky
} catch (Exception ex) {
  // handle an exception
} finally {
  // do any required cleanup
}

ist eine garantierte Möglichkeit, Code nach Ihrem try..catchBlock auszuführen , unabhängig davon, ob Ihr try-Block eine Ausnahme ausgelöst hat oder nicht.

Das macht es perfekt für Dinge wie das Freigeben von Ressourcen, Datenbankverbindungen, Dateihandles usw.

David Alpert
quelle
3
Alle diese Beispiele werden normalerweise besser mit einem using-Block bedient, aber das beeinträchtigt Ihre Antwort nicht wirklich.
Joel Coehoorn
4

Ich werde die Verwendung von schließlich mit einer Dateireader-Ausnahme erklären. Beispiel

  • ohne endlich zu benutzen
try{

  StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
  Console.WriteLine(strReader.ReadeToEnd());
  StreamReader.Close();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}

Wenn im obigen Beispiel die Datei mit dem Namen Data.txt fehlt, wird eine Ausnahme ausgelöst und behandelt, aber die aufgerufene AnweisungStreamReader.Close(); wird niemals ausgeführt.
Aus diesem Grund wurden die mit dem Leser verbundenen Ressourcen nie freigegeben.

  • Um das obige Problem zu lösen, verwenden wir schließlich
StreamReader strReader = null;
try{
    strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
    Console.WriteLine(strReader.ReadeToEnd());
}
catch (Exception ex){
    Console.WriteLine(ex.Message);
}
finally{
    if (strReader != null){
        StreamReader.Close();
    }
}

Viel Spaß beim Codieren :)

Hinweis: "@" wird verwendet, um eine wörtliche Zeichenfolge zu erstellen , um den Fehler "Nicht erkannte Escape-Sequenz" zu vermeiden. Das @ -Symbol bedeutet, diese Zeichenfolge wörtlich zu lesen und Steuerzeichen nicht anders zu interpretieren.

Ariven Nadar
quelle
2

Angenommen, Sie müssen den Cursor anstelle eines wartenden (Sanduhr-) Cursors auf den Standardzeiger zurücksetzen. Wenn vor dem Setzen des Cursors eine Ausnahme ausgelöst wird und die App nicht sofort abstürzt, kann ein verwirrender Cursor zurückbleiben.

Chris Doggett
quelle
2

Manchmal möchten Sie keine Ausnahme behandeln (kein catch-Block), aber Sie möchten, dass Bereinigungscode ausgeführt wird.

Beispielsweise:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}
Markom
quelle
Wenn die Ausnahme nicht abgefangen wird, hängt die Ausführung des finally-Blocks davon ab, ob das Betriebssystem eine Ausnahme-Abwicklungsoperation auslöst.
Vikas Verma
2

Der finally-Block ist nützlich, um alle im try-Block zugewiesenen Ressourcen zu bereinigen und Code auszuführen, der ausgeführt werden muss, auch wenn eine Ausnahme vorliegt. Die Steuerung wird immer an den finally-Block übergeben, unabhängig davon, wie der try-Block beendet wird.

cgreeno
quelle
1

Ahh ... ich glaube ich sehe was du sagst! Ich habe eine Sekunde gebraucht ... Sie fragen sich, "warum Sie es in den finally-Block anstatt nach dem finally-Block und vollständig außerhalb des try-catch-finally-Blocks legen".

Dies kann beispielsweise daran liegen, dass Sie die Ausführung anhalten, wenn Sie einen Fehler auslösen, aber dennoch Ressourcen wie geöffnete Dateien, Datenbankverbindungen usw. bereinigen möchten.

Beska
quelle
1

Der Kontrollfluss des finally-Blocks erfolgt entweder nach dem Try- oder dem Catch-Block.

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

mit Ausnahme 1> 2> 3> 4> 5, wenn 3 eine Return-Anweisung 1> 2> 3> 4 hat

ohne Ausnahme 1> 2> 4> 5, wenn 2 eine return-Anweisung 1> 2> 4 hat

Ranald Fong
quelle
0

Wie in der Dokumentation erwähnt :

Eine übliche Verwendung von catch und finally zusammen besteht darin, Ressourcen in einem try-Block abzurufen und zu verwenden, außergewöhnliche Umstände in einem catch-Block zu behandeln und die Ressourcen im finally-Block freizugeben.

Es lohnt sich auch das Lesen dieser , in der es heißt:

Sobald eine übereinstimmende catch-Klausel gefunden wurde, bereitet sich das System darauf vor, die Kontrolle auf die erste Anweisung der catch-Klausel zu übertragen. Bevor die Ausführung der catch-Klausel beginnt, führt das System zunächst alle finally-Klauseln aus, die mit try-Anweisungen verknüpft waren, die stärker verschachtelt sind als die, die die Ausnahme abgefangen haben.

Es ist also klar, dass Code, der sich in einer finallyKlausel befindet, auch dann ausgeführt wird, wenn eine vorherige catchKlausel eine returnAnweisung enthält.

Nexaspx
quelle