2009-07-07 4 views
4

Wie kann ich im folgenden Codeschnipsel sicherstellen, dass IDataReader entsorgt wird, wenn ExecuteReader eine Ausnahme auslöst?Wie kann ich ein IDisposable-Objekt bereitstellen, wenn die using-Anweisung eine Ausnahme auslöst?

using (IDataReader rdr = cmd.ExecuteReader()) 
{ 
    // use it 
} 

Es macht Sinn für mich, dass die using syntaktischen Zucker nicht Entsorgen nicht nennen (da es keinen Fall ist es zu fordern). Wie kann ich jedoch sicher sein, dass die knappen Ressourcen, die normalerweise von Klassen zugewiesen werden, die IDisposable implementieren, Freigaben sind?

+5

Wenn ExecuteReader eine Ausnahme auslöst, ist IDataReader null und muss nicht beseitigt werden. Die nicht verwalteten Ressourcen in ExecuteReader müssen bereinigt werden und sollten in einem eigenen finally-Block behandelt werden. – cjk

Antwort

14

Wenn ExecuteReader in Ihrem Beispiel eine Ausnahme auslöst, gibt es nie etwas zurück. Es liegt dann an der Implementierung von ExecuteReader, alles zu beseitigen, was vor der Ausnahme erstellt wurde.

+0

Richtig, also wird es die Verantwortung des Werfers der Ausnahme, aufzuräumen, wenn eine Ausnahme ausgelöst wird? – jpoh

+3

@jpoh - es ** muss ** sein, der Aufrufer hat keine Objekte, die versucht aufzuräumen Am schlimmsten ist, dass der Finalizer startet. –

-2

Ich dachte, dass die Anweisung using auf die IL übersetzt wurde, die ähnlich ist:

try 
{ 
} 
finally 
{ 
    disposableUsedObject.Dispose(); 
} 

Also, ich würde denken, dass unter normalen Umständen sollte die Entsorgung genannt werden?

Auch sollten Sie keine Ausnahmen innerhalb des Konstruktors werfen, da Benutzer nicht erwarten, dass eine Ausnahme ausgelöst wird, wenn sie ein Objekt instanziieren. Ich würde die Initialisierungslogik verschieben, die eine Ausnahme zu einer anderen Methode (Initialize) auslösen kann, die nach dem Instanziieren des Objekts aufgerufen werden muss.

+1

Aber wenn der Konstruktor die Ausnahme auslöst, gibt es kein Objekt zu entsorgen? – cjk

+0

@ck Genau mein Problem – jpoh

+0

Sie sollten Ausnahmen in einem Konstruktor nicht werfen, da dies ein wenig unerwartet ist. Benutzer Ihrer Klasse erwarten nicht, dass eine Ausnahme in einem Konstruktor/beim Instanziieren eines Objekts ausgelöst werden kann. :) Ich denke, es ist besser, diese Initialisierungslogik zu verschieben (das kann eine Ausnahme auf eine andere Methode trimmen (Initialize oder so) –

3

Wenn der Konstruktor eines Objekts nicht ausgeführt werden kann, haben Sie kein Objekt, das entsorgt werden muss.

Wenn Sie einen Konstruktor schreiben, der eine Ausnahme auslösen könnte, sollten Sie sicherstellen, dass Sie alles bereinigen, das Sie benötigen, indem Sie using oder try-catch-Block verwenden.

In Ihrem IDataReader-Beispiel genügt es, das Befehlsobjekt einfach zu entfernen, wenn der Methodenaufruf cmd.ExecuteReader() fehlschlägt.

+0

Um zu verdeutlichen, was Matt gesagt hat, benutze/try catch innerhalb des Konstruktors deiner wegwerfbaren Klasse, damit er seine eigenen internen Ressourcen richtig entsorgt. Ich lehne mehr in Richtung Versuch fangen, da die Ressource eine Ressource auf Klassenebene und nicht nur Konstruktor Ebene sein könnte. Wenn dies der Fall ist, ist die Verwendung angemessener. –

0

Verschieben des Codes, der die Initialisierung außerhalb des Konstruktors ausführt, in eine separate Funktion. Im Wesentlichen werden Sie haben

+0

Dies ist nicht notwendig. Wenn der Konstruktor erneut ausgibt, gibt es nichts zu bereinigen. –