2009-11-27 8 views
22

Normalerweise verwende ich Code wie folgt:Ist SqlCommand.Dispose() erforderlich, wenn die zugeordnete SqlConnection entfernt wird?

using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString)) 
{ 
    var command = connection.CreateCommand(); 
    command.CommandText = "..."; 
    connection.Open(); 
    command.ExecuteNonQuery(); 
} 

Wird mein command automatisch entsorgt? Oder nicht und ich muss es in using Block wickeln? Ist es erforderlich, SqlCommand zu entsorgen?

+0

Es ist schade, dass Microsoft SqlCommand zu einer Komponente gemacht hat. Wenn sie wirklich eine Komponente für die Designerunterstützung benötigen, könnte es sich um einen Wrapper für einen einfachen SqlCommand handeln, der IDisposable nicht implementiert. –

Antwort

22

Genau dies tun:

using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString)) 
using(var command = connection.CreateCommand()) 
{ 
    command.CommandText = "..."; 
    connection.Open(); 
    command.ExecuteNonQuery(); 
} 

Nicht auf dem Befehl entsorgen Aufruf wird nicht so schlimm nichts tun. Aber das Aufrufen von Dispose wird supress the call to the finalizer, Anrufer machen eine Leistungssteigerung zu entsorgen.

+11

"Nicht anrufen über den Befehl zu disponentieren wird nichts zu schlecht machen." Stimmt, aber gewöhne dich nicht daran; Das gilt nur für 'SqlCommand's. Wenn Sie andererseits zum Beispiel keinen 'SqlCeCommand' anordnen, * wird Ihr mobiles Gerät ziemlich schnell aus dem Speicher gehen. (Einfach da gewesen, das getan ...) – Heinzi

+2

'Dispose' unterdrückt die Finalisierung nicht, da der Konstruktor das tut. –

8

Die sicherste Richtlinie ist, immer Dispose() für ein Objekt aufzurufen, wenn es IDisposable entweder explizit oder über einen using-Block implementiert. Es kann Fälle geben, in denen es nicht erforderlich ist, aber es trotzdem aufzurufen, sollte nie Probleme verursachen (wenn die Klasse korrekt geschrieben wird). Außerdem wissen Sie nie, wann eine Implementierung die Bedeutung ändern könnte, wo der Aufruf zuvor nicht erforderlich war, ist er jetzt definitiv erforderlich.

In dem Beispiel, das Sie angegeben haben, können Sie einen zusätzlichen inneren using-Block für den Befehl hinzufügen sowie den äußeren using-Block für die Verbindung beibehalten.

+2

Ja, die sicherste Richtlinie ist, dass Sie wegwerfbare Objekte immer entsorgen - vor allem, wenn Sie sie * erstellt haben! Es ist beispielsweise keine gute Idee, eine Methode zu schreiben, die einen Stream akzeptiert, und den Stream innerhalb dieser Methode zu verteilen. Ein weiterer Nachteil ist, dass Sie nicht immer über die using-Anweisung ungestraft verfügen können. WCF-Proxies sind das einzige praktische Beispiel, das ich kenne. Wenn am entfernten Ende etwas schief geht und Sie eine Ausnahme erhalten, wird der Kanal geschlossen und Dispose löst dann eine neue Ausnahme aus, die die ursprüngliche Ausnahme ersetzt, was ein ernstes Problem sein kann. –

+1

ein weiterer Grund, WCF nicht zu verwenden! danke für den tipp aus ;-) –

1

Sie können diese Art von Sachen mit Reflector herausfinden.

Ich hatte eine kleine Ausgrabung (ich würde vorschlagen, dass Sie sich selbst graben, um ganz sicher zu sein von dem Rest, obwohl ich nicht so hart versuchte) und es sieht so aus, als wenn Sie eine Verbindung töten, gibt es keine Verfügung von irgendwelchen Kindern, die mit dieser Verbindung verbunden sind. Außerdem sieht es eigentlich nicht so aus, als würde die Entsorgung eines Befehls tatsächlich so viel bewirken. Es wird ein Feld auf null setzen, sich von einem Container lösen (dies kann einen Speicherleck verhindern) und ein Ereignis auslösen (das ist zwar wichtig, aber ich kann nicht sehen, wer dieses Ereignis hört).

In beiden Fällen ist es ratsam, dieses Zeug in einem Verwendungsblock zu verwenden oder sicherzustellen, dass Sie es mit einem Verfügungsmuster in dem Objekt entfernen, das die Verbindung enthält (wenn Sie den Befehl eine Weile halten).

4

Ja, sollten Sie, auch wenn es die Implementierung derzeit nicht viel tut, Sie nicht wissen, wie es in der Zukunft (neuere Framework-Versionen zum Beispiel) geändert wird. Im Allgemeinen sollten Sie alle Objekte, die IDisposable implementieren, auf der sicheren Seite entsorgen.

Wenn jedoch die Operation verschoben wird und Sie haben keine Kontrolle über den vollen Umfang (zum Beispiel, wenn asynchron arbeiten, oder wenn ein SqlDataReader oder so zurückkehrt), können Sie die CommandBehavior zu CloseConnection, so dass, sobald der Leser eingestellt ist fertig, die Verbindung ist für Sie richtig geschlossen/entsorgt.

2

In der Praxis können Sie Dispose überspringen. Es gibt keine Ressourcen frei. Es unterdrückt nicht einmal die Finalisierung, da der Konstruktor das tut.

In der Theorie könnte Microsoft die Implementierung ändern, um eine nicht verwaltete Ressource zu übernehmen, aber ich würde hoffen, dass sie mit einer API herauskommen würde, die die Component Basisklasse lange bevor sie das tun würde.

Verwandte Themen