2010-09-03 9 views
6

Ich verwende die using-Anweisung für SqlConnection. Es ist gut für die Leistung, da Forces Dispose() aufrufen, die die Verbindung zu dem Pool einfach früher freigibt.Kann die using-Anweisung durch geschweifte Klammern ersetzt werden?

Allerdings habe ich festgestellt, dass in Verwendung erstellt Objekt nicht neu definiert werden kann. Ich kann so nicht tun:

using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 
     //... 
     connection = new SqlConnection(connectionString2); 
     //... 
     connection = new SqlConnection(connectionString3); 
    } 

ich mich gefragt, ob ich mit ersetzen kann, und etwas tun, wie folgt aus:

{ 
     SqlConnection connection = new SqlConnection(connectionString); 

     connection.Open(); 
     //... 
     connection = new SqlConnection(connectionString2); 
     //... 
     connection = new SqlConnection(connectionString3); 
} 

Die SqlConnection wird nicht nach der letzten } Klammer zugänglich sein. Wird das Dispose() sofort aufgerufen, wenn das Objekt seinen Gültigkeitsbereich verlässt?

Antwort

13

Nein, die Dinge werden in Ihrem zweiten Beispiel nicht automatisch bereinigt (in der Tat, mit dem Code, den Sie haben, lassen Sie mehrere Verbindungen hängen offen).

Nicht nur das, aber Sie verlieren die automatische Bereinigung im Falle von Ausnahmen im using Block geworfen werden. Denken Sie daran, dass ein using Block zerfällt in:

SqlConnection connection = new SqlConnection(connectionString); 
try 
{ 
    connection.Open(); 
    // Do work 
} 
finally 
{ 
    connection.Dispose(); 
} 

Wenn Sie wirklich verschiedene Verbindungen verwenden, und jede Verbindung beseitigt werden am Ende des Blockes, würde ich mehr mit Blöcke verwenden:

using(SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    // Do Work 
} 

// First connection is disposed 

using(SqlConnection connection = new SqlConnection(connectionString2)) 
{ 
    // Do More Work 
} 

// Second connection is disposed 

using(SqlConnection connection = new SqlConnection(connectionString3)) 
{ 
    // Do More Work 
} 

// Last connection is dipsosed 
+0

Danke. Wenn es um das Schließen von Verbindungen geht, würde ich natürlich connection.Close() anrufen, aber ich habe es nicht in den obigen Code geschrieben. – nan

+1

Auch wenn Sie Close() explizit aufrufen, kann Ihr zweites Beispiel dennoch eine Verbindung offen lassen, wenn eine Ausnahme auftritt. Der Aufruf von Dispose wird nicht nur ausgeführt, wenn die Ausführung diesen Block verlässt, sondern auch, wenn eine Ausnahme auftritt. – ThatBlairGuy

3

Nein, mit dem Erstellen werden einige spezielle Clean-up-Konstrukte erstellt, die Sie nicht nur mit den Klammern erhalten.

Wenn Sie Reflektor verwenden und Blick auf die IL gibt es einen Anruf am Ende des using-Blocks für sein Ziel hinzugefügt zu entsorgen:

L_0006: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string) 
L_000b: stloc.0 
L_000c: nop 
L_000d: nop 
L_000e: leave.s L_0020 
L_0010: ldloc.0 
L_0011: ldnull 
L_0012: ceq 
L_0014: stloc.1 
L_0015: ldloc.1 
L_0016: brtrue.s L_001f 
L_0018: ldloc.0 
**L_0019: callvirt instance void [mscorlib]System.IDisposable::Dispose()** 
L_001e: nop 
L_001f: endfinally 

Dies erklärt, warum Sie nicht eine neue Verbindung innerhalb der anlegen Block verwenden und der Variablen zuweisen - dies würde dazu führen, dass die ursprüngliche Referenz hängen bleibt und nicht verschoben wird.

+1

Ich denke, es ruft Dispose() auf IDisposable Objekte ... weiß nicht sicher –

+1

@Mike - Sie können 'using' nur auf IDisposable Objekte verwenden, weil es Dispose() ruft – annakata

+3

Es ruft tatsächlich' ((IDisposable) blah) .Dispose() ', wobei' blah' die verwendete Variable ist. Es kompiliert nicht, wenn der Typ 'IDisposable' nicht implementiert. – Timwi

3

Nein, wird nach der schließenden geschweiften Klammer nicht aufgerufen. Sie müssen es manuell aufrufen oder eine using-Anweisung verwenden.

Wenn Sie das Dispose nicht ausführen, wird es ausgeführt, wenn der Finalize aufgerufen wird. Und hier haben Sie 2 Probleme

  • Ausführen einer Finalize-Methode ist teuer in der Leistung. Wenn Ihre Dispose-Methode die Säuberung des Objekts bereits durchgeführt hat, muss der Garbage Collector nicht die Finalize-Methode des Objekts aufrufen (falls sie gut implementiert ist, sollte eine Dispose-Methode die SuppressFinalize-Methode für das Objekt, das sie entsorgt, aufrufen). (MSDN)
  • Sie kontrollieren nicht den Moment, wenn die Finalisierung automatisch aufgerufen wird und nicht ausgeführt werden konnte (zum Beispiel wegen eines Absturzes).
8

Die using Aussage ist syntaktischer Zucker, die innerhalb des () initialisiert Dispose auf die Objekte aufruft, so kann man einfach nicht ersetzen, wie Sie in Ihrem Beispiel haben.

Sie werden feststellen, dass die einzigen Objekte, die Sie innerhalb einer using Anweisung diejenigen, die IDisposable implementieren sind verwenden können, die aufgerufen werden kann, dass Dispose gewährleistet.

Wie this Artikel erläutert, wird der Compiler diese Transformation:

using (MyResource myRes = new MyResource()) 
{ 
    myRes.DoSomething(); 

} 

Um dies:

MyResource myRes= new MyResource(); 
try 
{ 
    myRes.DoSomething(); 
} 
finally 
{ 
    if (myRes!= null) 
     ((IDisposable)myRes).Dispose(); 
} 

Also, wenn Sie diese Struktur duplizieren, werden Sie nicht das gleiche Verhalten bekommen.

Darüber hinaus - die Wiederverwendung einer Variablen, wie Sie in Ihrem Beispiel sind, ist eine schlechte Übung.Jemand, der den Code liest, kann denken, dass er Verbindung 1 betrachtet, wenn er tatsächlich auf 2 oder 3 schaut. Das könnte sehr verwirrend sein und alle möglichen Probleme verursachen.

+0

Nun habe ich versucht, Usings loszuwerden, weil ich eine Menge davon habe (ich verwende sie auch häufig mit 'Streams' in meinem Projekt). Der zweite Grund ist, dass ich viele sequenzielle Verbindungen habe, also habe ich darüber nachgedacht, ein Objekt zu verwenden. Ich wollte die Lesbarkeit erhöhen, aber Sie haben Recht, es könnte es nur verringern. – nan

3
using(foo) 
{ 
    // stuff 
} 

... ist ein bisschen Zucker, die in übersetzt:

try 
{ 
    // stuff 
} 
finally 
{ 
    foo.Dispose() 
} 

Während:

{ 
    // stuff 
} 

... übersetzt nichts. Es ist einfach:

{ 
    // stuff 
} 

: D

Edit:.. Bitte nicht zerstören die Formatierung, wenn Sie :(

2

Nein bearbeiten, können Sie dies nicht tun können, zumindest in C#

Aber Sie können verschiedene Einweg-Objekte innerhalb einer using-Anweisung erstellen:

using (SqlConnection connection1 = new SqlConnection(connectionString1), 
      connection2 = new SqlConnection(connectionString2), 
      connection3 = new SqlConnection(connectionString3)) 
    { 
     connection1.Open(); 
     //... 
     connection2.Open(); 
     //... 
     connection3.Open(); 
    } 

C++/CLI Sie Ihre Einweg-Klassen in stapelartigen faision verwenden:

void MyClass::Foo() 
{ 

{ 
    SqlConnection connection(connectionString); 
    //connection still allocated on the managed heap 
    connection.Open(); 
    ... 
    //connection will be automatically disposed 
    //when the object gets out of scope 
} 


{ 
    SqlConnection connection(connectionString2); 
    connection2.Open(); 
    ... 
} 

} 
+0

+1 für nette 'usings' Gruppierung, wusste nicht darüber – nan

1

ich das auch dachte zuerst ... aber anscheinend, wenn die Verwendung von Blockende, .Dispose() auf dem Objekt aufgerufen wird, das ist anders als das Objekt außerhalb der Reichweite zu lassen. Da es sich bei C# um eine in der Garbage Collection gesammelte Sprache handelt, kann es eine Weile dauern, bis das Objekt tatsächlich bereinigt wurde. Der Baustein using stellt sicher, dass er sofort und unabhängig von Ausnahmen entsorgt wird.