2009-02-05 11 views
24

diesen Code Gegeben:Wie fangen Sie Ausnahmen mit "using" in C#

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 
} 

Ich bin für meine Datenzugriff auf das Schreiben try/catch/finally Blöcke verwendet, aber ich bin zu ausgesetzt "using", das scheint eine viel einfachere Methode zu sein, dies zu tun. Ich versuche jedoch herauszufinden, wie Sie eventuell auftretende Ausnahmen abfangen können.

Könnten Sie mir bitte ein Beispiel geben, wie Sie Ausnahmen bekommen?

Edited hinzufügen:

Ich führe ich bin zu glauben, dass "mit" ist ein Ersatz für meine try/catch/finally Blöcke. Ich verstehe, dass die Verwendung keine Ausnahmen feststellt. Also, wie ist das ein Ersatz?

+2

Es ist kein Ersatz. –

Antwort

47

using ist nicht konzipiert, um Ausnahmen zu erfassen; Es wurde entwickelt, um Ihnen eine einfache Möglichkeit zu geben, ein try/finally um ein Objekt zu wickeln, das entsorgt werden muss. Wenn Sie Ausnahmen abfangen und behandeln müssen, müssen Sie es in eine vollständige try/catch/finally oder eine try/catch um die ganze Sache zu erweitern.


Ihre bearbeiten zu beantworten (ist using ein Ersatz für try/catch/finally?), Dann nein, es ist nicht. Die meiste Zeit, wenn Sie eine wegwerfbare Ressource benutzen, werden Sie nicht die Ausnahme dort behandeln und dann, weil es normalerweise nichts nützliches gibt, das Sie tun können. Es stellt also eine bequeme Möglichkeit dar, um sicherzustellen, dass die Ressource unabhängig davon, was Sie versuchen zu arbeiten, bereinigt wird.

Normalerweise arbeitet Code, der mit verfügbaren Ressourcen arbeitet, zu niedrig, um zu entscheiden, welche Aktion bei einem Fehler ausgeführt wird. Daher wird die Ausnahme an den Aufrufer weitergegeben, der entscheiden kann, welche Aktion ausgeführt werden soll (z. B. wiederholen, fehlschlagen) , log, usw.). Der einzige Ort, an dem Sie einen catch Block mit einer Einweg-Ressource verwenden würden, ist, wenn Sie die Ausnahme übersetzen (was ich davon ausgehe, was Ihre Datenzugriffsschicht tut).

6

Die Verwendung von Anweisungen hat nichts mit Ausnahmen zu tun. Die Verwendung von Blöcken stellt sicher, dass Dispose für das Objekt im using-Block aufgerufen wird, wenn es diesen Block verlässt. I.E:

using(SqlConnection conn = new SqlConnection(conStr)) 
{ 
    //use conn 
}//Dispose is called here on conn. 

Wenn Öffnen der Verbindung löst eine Ausnahme (oder irgendetwas anderes in diesem Block für diese Angelegenheit) wird es noch Blase nach oben und wird wie jede andere unhanded Ausnahme sein.

7

Wenn Sie Ausnahmen abfangen wollen, sollten Sie wahrscheinlich wieder versuchen/fangen/endlich. Setzen Sie einfach die .Dispose() -Aufrufe in den finally-Block.

+1

Er kann den using in einen try/catch-block verpacken. Wenn ein Fehler festgestellt wird, wird Dispose aufgerufen (falls vorhanden), bevor der Fang eingegeben wird. – Leonidas

+2

Das ist wahr, aber dann haben Sie eine weitere Ebene der Einrückung und die Verwendung Aussage ist nicht mehr so ​​bequem. Ich würde es vorziehen, wenn ich nur versuche, alles zu versuchen/zu fangen/endlich zu handhaben (aber das ist eine kleine Stilsache). –

+1

Aber selbst mit einfacher Fehlerbehandlung kann es leicht sein, Code zu schreiben, der so aussieht, als würde er 'Dispose()' aufrufen, aber in einigen Fällen fehlschlägt. 'using()' stellt zumindest sicher, dass es korrekt bereinigt wird, selbst wenn es eine granulare Ausnahmebehandlung fast unmöglich macht. – binki

8

Wickeln Sie alle using-Anweisungen in einen try/catch. Wie jeder andere gesagt hat, ist mit für die Klassen Reinigung, die die IDisposable-Schnittstelle

try 
{ 

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 
} 
} 
catch(Exception ex) 
{ 
//Handle, log, rethrow exception 
} 
+0

Wie ist das besser, dass try/catch/finally und calling dispose in meinem finally block? – GregD

+0

Erik, warum würdest du im finally block dispoten? Wann können Sie die using-Anweisungen verwenden? Wenn Sie den finally-Block verwenden, müssen Sie die Objekte außerhalb des try-Blocks deklarieren ... –

+0

Intern ist das die gleiche IL, die using-Anweisung generiert Charles. Es ist wirklich nur syntaktische Süßigkeiten. –

3

Sie noch (oder ignorieren) Ausnahmen implementieren genau fangen, wie Sie vorher haben würde. Der Punkt ist, dass Sie sich nicht mehr um die Entsorgung der Datenbankverbindung kümmern müssen.

dh Wenn Ihre Anwendung erfordert, dass Sie Trap-Ausnahmen aus einem anderen Grunde (zB Logging) dann gehen Sie vor, aber Sie müssen nicht mehr so ​​tun, wenn Sie nur die Datenbankverbindung zur Entsorgung:

using (SqlConnection conn = new SqlConnection(...)) 
{ 
    // do your db work here 
    // whatever happens the connection will be safely disposed 
} 

Wenn Sie die Ausnahme aus einem anderen Grund fangen wollen, können Sie immer noch so tun:

try 
{ 
    using (SqlConnection conn = new SqlConnection(...)) 
    { 
     // do your db work here 
     // whatever happens the connection will be safely disposed 
    } 
} 
catch (Exception ex) 
{ 
    // do your stuff here (eg, logging) 
    // nb: the connection will already have been disposed at this point 
} 
finally 
{ 
    // if you need it 
} 
+0

Das ist lustig. Ich habe mich gefragt, ob du deinen Kopf hier rein steckst :) – GregD

10
using (var cmd = new SqlCommand("SELECT * FROM Customers")) 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 

ist syntaktischer Zucker für

var cmd = new SqlCommand("SELECT * FROM Customers"); 
try 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 
finally 
{ 
    if (cmd != null) 
     cmd.Dispose(); 
} 

Also, wenn Menschen, die Sie sagen, dass „mit“ ist ein Ersatz für try/catch/finally, dass sie impliziert Sie die lange Hand Formular verwendet werden sollte, aber in Ihrem Catch-Block hinzufügen:

var cmd = new SqlCommand("SELECT * FROM Customers"); 
try 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 
catch (Exception ex) 
{ 
    ...//your stuff here 
} 
finally 
{ 
    if (cmd != null) 
     cmd.Dispose(); 
} 
+0

Wenn cmd im try-Block erstellt wird, kannst du im finally-Block nicht darüber verfügen. – Kredns

+1

@Lucas Aardvark - natürlich, Danke! Fest. – RogueBadger