2009-05-27 6 views
8

Ich habe eine sqlConnection Managerklasse wie folgt:Verwenden Sie die 'using'-Anweisung von C# mit der Funktion eines benutzerdefinierten Objekts, muss IDisposable implementiert werden?

public class SQLConn { 
    public string connStr = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"]; 

    private SqlConnection sqlConn; 

    public SqlConnection Connection() 
    { 
     sqlConn = new SqlConnection(connStr); 

     return sqlConn; 
    } 

    public void Open() 
    { 
     sqlConn .Open(); 
    } 
} 

Wenn ich eine Funktion mit der Aussage wie ‚mit‘:

var conn = new SQLConn(); 

using (conn.Connection()) 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, conn.Connection());  

    conn.Open(); 
    DoSomething(); 
} 

Ist die Anweisung using dispose der Verbindung automatisch, da conn.Connection() zurückkehren ein SqlConnection-Objekt? Oder muss ich IDisposable und eine benutzerdefinierte Dispose-Methode für die SqlConn-Klasse implementieren?

Ist das überhaupt ein guter Weg? Ich arbeite mit Legacy-Code und kann noch kein ORM verwenden, aber gibt es eine Möglichkeit, dieses bestehende Muster zum Verwalten/Erstellen von SQL-Verbindungen zu vereinfachen?

Antwort

12

Die using Anweisung wird den endgültigen Typ des Ausdrucks betrachten - d. H. Was auch immer von .Connection() zurückgegeben wird; Wenn dies etwas zurückgibt, das IDisposable ist, dann bist du OK.

Der Compiler wird Ihnen sagen, wenn Sie es falsch bekommen ;-p (es wird nicht using auf etwas verwenden, das nicht IDisposable ist).

Sie sollten wahrscheinlich passen Sie auf, wo Sie zwei Verbindungen schaffen:

using (var c = conn.Connection()) // <==edit 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, c); // <==edit 

    c.Open(); 
    DoSomething(); 
} 

und möglicherweise:

public SqlConnection Connection() 
{ 
    if(sqlConn == null) sqlConn = new SqlConnection(connStr); // <== edit 
    return sqlConn; 
} 
0

Nein, nicht, solange das zurückgegebene Objekt IDisposable ist.

Das zurückgegebene Objekt muss IDisposable nicht implementieren, aber dann würde der using-Block keinen Zweck erfüllen.

+0

Die letzte Art des Ausdrucks * * IDisposable implementieren muss: Fehler ‚Bar‘: In einer using-Anweisung verwendet wird, muss ‚System.IDisposable implizit konvertierbar sein –

+0

Hmmm, interessant ist, dass veränderte Verhalten von vorherige Versionen des Compilers, oder habe ich es einfach nur vermisst, verstanden? – leppie

+1

Ich bin mir einer Änderung nicht bewusst (aber ich habe in letzter Zeit nicht die 1.2 Spezifikation angeschaut). Denken Sie vielleicht an 'foreach'? wo könnte der Enumerator * wegwerfbar sein (und wenn ja, ist entsorgt), muss es aber nicht sein? Oder vielleicht die Tatsache, dass der zurückgegebene Wert Null sein darf? –

0

Von MSDN:

das Objekt an die vorgesehenen mit Anweisung muss implementieren die IDisposable Schnittstelle.

Sie müssen Dispose() nicht aufrufen, die using-Anweisung macht das implizit für Sie.

5

Es wird funktionieren, aber nach der using {} werden Sie mit einem sqlConn verlassen, die intern eine Disposed SqlConnection enthält. Keine wirklich nützliche Situation

1

Ihr Code ist falsch!

shoudl so etwas wie diese:

Dim conn as New SQLConn(); 
Dim sqlConnection New SQLConnection(); 

sqlConnection = conn.Connection(); 

using (sqlConnection) 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, sqlConnection);  

    conn.Open(); 
    DoSomething(); 
} 

diese Weise die using-Anweisung wird die Verbindung am Ende verfügen.

+1

Warum erstellen Sie zwei SqlConnections? Mindestens eins wird nicht entsorgt. – Ruben

+0

+1 Das Problem liegt nicht beim Schreiben von 'using (conn.Connection())', sondern daran, dass die 'Connection()' Methode jedes Mal ein neues Objekt erstellt, wenn sie aufgerufen wird. und im ursprünglichen Post ist die Verbindung, die sich unter dem "using" befindet, keine andere Instanz als die Verbindung, die tatsächlich innerhalb des Blocks verwendet wird. –

+0

Sie brauchen wahrscheinlich nicht die "New SQLConnection", dann –

0

Es scheint, die Verbindung ordnungsgemäß geschlossen werden, aber dies wird nicht empfohlen:

Sie das Objekt Ressource instanziiert und dann die Variable übergeben Sie die Anweisung using , aber dies ist kein besten trainieren. In diesem Fall bleibt das Objekt im Bereich, nachdem die Steuerung den using-Block verlassen hat, obwohl er wahrscheinlich nicht mehr auf Zugriff auf seine nicht verwalteten Ressourcen hat. In anderen Worten wird es nicht mehr vollständig initialisiert. Wenn Sie versuchen, das Objekt außerhalb des verwendeten Blocks zu verwenden, riskieren Sie, dass eine Ausnahme verursacht, die ausgelöst wird. Aus diesem Grund ist es im Allgemeinen besser, das Objekt in der using-Anweisung zu instanziieren und seinen Geltungsbereich auf den using-Block zu beschränken.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

1

Ihre Überschrift Frage zu beantworten, Sie IDisposable in der Klasse, deren Objekt implementieren müssen Sie verwenden mit „verwenden“. Andernfalls erhalten Sie einen Fehler bei der Kompilierung.

Dann ja, "verwenden" wird Ihre SqlConnection am Ende des Blocks entsorgen. Stellen Sie sich "Verwendung" als "try-finally" vor: Es gibt einen impliziten Aufruf von Dispose() im "finally" -Block.

Schließlich saubereren Code wäre:

using(SqlConnection = new SqlConnection(connStr) { 
    // do something 
} 

Mindestens Leser Ihres Codes als Henk Holterman wies darauf hin, nicht die geistige Anstrengung machen müssen, um zu erkennen, dass Ihr SQLConn Objekt einen Verweis auf eine angeordnete hält Verbindung.

1

Um zu klären, was oben gesagt wird:

Alle Sie Objekt verwenden müssen sollte am Ende der Anweisung using mit der Verwendung entsorgt werden. Der Compiler muss also sicherstellen, dass Ihr Typ die IDisposable-Schnittstelle implementiert, wenn er sieht, dass er dieses Objekt verwendet, oder er lässt Sie nicht los.