Czy muszę zamykać () połączenie SQLConnection, zanim zostanie usunięte?

113

Zgodnie z moim innym pytaniem dotyczącym obiektów jednorazowego użytku , czy powinniśmy wywołać Close () przed końcem using bloku?

using (SqlConnection connection = new SqlConnection())
using (SqlCommand command = new SqlCommand())
{
    command.CommandText = "INSERT INTO YourMom (Amount) VALUES (1)";
    command.CommandType = System.Data.CommandType.Text;

    connection.Open();
    command.ExecuteNonQuery();

    // Is this call necessary?
    connection.Close();
}
John Bubriski
źródło

Odpowiedzi:

107

Ponieważ masz using blok, zostanie wywołana metoda Dispose SQLCommand, która zamknie połączenie:

// System.Data.SqlClient.SqlConnection.Dispose disassemble
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }
    this.DisposeMe(disposing);
    base.Dispose(disposing);
}
CMS
źródło
1
Czy this._poolGroup = null; oznacza, że ​​połączenie nie wraca do puli połączeń? więc będę miał n-1 połączeń?
Royi Namir
25

Demontaż SqlConnection przy użyciu .NET Reflector :

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }

    this.DisposeMe(disposing);
    base.Dispose(disposing);
}

Wywołuje Close () wewnątrz Dispose ()

statenjason
źródło
1
@statenjason: czy mógłbyś powiedzieć, jak możesz skorzystać z używania reflektora deasemblers line .net?
odiseh
3
@odiseh po prostu pobierz .NET Reflector, uruchom reflector.exe i możesz otworzyć dowolną bibliotekę DLL .net (w tym bibliotekę standardową). Zapewnia strukturę drzewa podobną do przeglądarki obiektów programu Visual Studio, jednak można kliknąć prawym przyciskiem myszy dowolną klasę lub metodę i kliknąć opcję „demontaż”, a następnie zwróci źródło w języku C # lub VB, w zależności od tego, co zostało wybrane w opcje.
statenjason
20

Słowo kluczowe using spowoduje prawidłowe zamknięcie połączenia, więc dodatkowe wywołanie Close nie jest wymagane.

Z artykułu MSDN na temat puli połączeń programu SQL Server :

„Zdecydowanie zalecamy, aby zawsze zamykać połączenie po zakończeniu korzystania z niego, aby połączenie zostało zwrócone do puli. Można to zrobić za pomocą metod Close lub Dispose obiektu Connection lub otwierając wszystkie połączenia wewnątrz using instrukcja w C # "

Rzeczywista implementacja SqlConnection.Dispose przy użyciu .NET Reflector jest następująca:

// System.Data.SqlClient.SqlConnection.Dispose disassemble
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }
    this.DisposeMe(disposing);
    base.Dispose(disposing);
}
Thomas Bratt
źródło
1
+1 dla łącza MSDN - lubię reflector \ ILspy jak następny facet, ale dokumenty są tam, gdzie chciałbym znaleźć moje odpowiedzi.
mlhDev
5

Używając Reflectora , możesz zobaczyć, że Disposemetoda SqlConnectionfaktycznie wywołuje Close();

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }
    this.DisposeMe(disposing);
    base.Dispose(disposing);
}
Aaron Daniels
źródło
3

Nie, blok Using Dispose()i tak dzwoni , więc nie ma potrzeby dzwonić Close().

Jason Evans
źródło
Przepraszam, powinienem był powiedzieć, że dla większości obiektów, które implementują IDisposable i mają metodę Close (), wywołanie Close () i tak kończy się wywołaniem Dispose () za kulisami.
Jason Evans
6
Czy nie jest na odwrót - Dispose()rozmowy Close(), a nie odwrotnie?
Miasto
1
Zwykle jest to jedno i drugie. Z jakiegoś powodu zdecydowali się wdrożyć, że Close będzie również nazywać Dispose. W przypadku SqlConnection nie jest to wielka sprawa, ale StreamWriters zgłosi wyjątek, jeśli je zamkniesz, a następnie usuniesz. Domyślam się, że nie zmienią tego zachowania tylko dlatego, że ludzie tego właśnie oczekują.
2

Nie, nie jest konieczne zamykanie połączenia przed wywołaniem funkcji Dispose.

Niektóre obiekty (takie jak SQLConnections) mogą być ponownie użyte po wywołaniu Close, ale nie po wywołaniu Dispose. W przypadku innych obiektów wywołanie Close jest takie samo, jak wywołanie Dispose. (Myślę, że ManualResetEvent i strumienie zachowują się w ten sposób)

pipTheGeek
źródło
1

Nie, klasa SqlConnection dziedziczy po IDisposable, a po napotkaniu końca using (dla obiektu połączenia) automatycznie wywołuje Dispose w klasie SqlConnection.

blparker
źródło