"kullanma" bloğunda bir SqlConnection iade veya istisna kapalı mı?


136

İlk soru:
Diyelim ki

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}

Bağlantı kapanıyor mu? Çünkü teknik olarak asla }eskisi gibi son returnbulmayız.

İkinci soru:
Bu sefer:

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        int employeeID = findEmployeeID();

        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();
    }
}
catch (Exception) { /*Handle error*/ }

Şimdi, bir yerlerde trybir hata alıp yakalandığımızı söyleyin . Bağlantı hala kapanıyor mu? Çünkü yine, kodun geri kalanını atlıyoruz tryve doğrudan catchifadeye gidiyoruz .

Nasıl usingçalıştığı konusunda çok doğrusal düşünüyor muyum ? Yani kapsamdan Dispose()ayrıldığımızda sadece çağırılıyor usingmu?

Yanıtlar:


178
  1. Evet
  2. Evet.

Her iki durumda da, kullanım bloğundan çıkıldığında (başarılı bir şekilde tamamlandığında veya yanlışlıkla) kapatılır.

Böyle organize olmanın daha iyi olacağını düşünmeme rağmen , daha sonra destekleyecek yeni bakım programcısı için bile ne olacağını görmek çok daha kolay:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{    
    int employeeID = findEmployeeID();    
    try    
    {
        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();    
    } 
    catch (Exception) 
    { 
        /*Handle error*/ 
    }
}

3
@TrueWill - Kabul ediyorum. Ben sadece yapısı için kodu biraz hareket ettirdi.
David

10
Soru: Using deyimini kullanırken bir bağlantıyı AÇIK hale getirmem gerekiyor mu?
fandango68

3
Ayrıca işlemleri kullanıyorsanız, try catchiçinde bulundurarak usingaçıkça .Commitveya içindeki .Rollbackişlemleri yapabilirsiniz catch. Bu hem daha okunabilir hem de açıktır ve istisnanın türü göz önüne alındığında bunun mantıklı olup olmadığını taahhüt etmenizi sağlar. (İşlemler conn.Closetaahhüt edilmezse dolaylı olarak geri alınır .).
Chris

8
@ Fernando68 Evet, hala Openbağlantıya ihtiyacınız var. usingyalnızca nesnenin Disposeyönteminin çağrıldığını garanti eder .
juharr

Blokları kullanarak içinde ExecuteScalar dönüş var. Ve yöntemi ikinci kez çalıştırdığımda bağlantı açık olduğu gibi çok hızlı. İkinci sefer neden bu kadar hızlı?
olumlu perspektif

46

Her iki soruya da evet. Using ifadesi bir try / nihayet bloğunda derlenir

using (SqlConnection connection = new SqlConnection(connectionString))
{
}

aynıdır

SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
}
finally
{
   if(connection != null)
        ((IDisposable)connection).Dispose();
}

Düzenleme: Oyuncuyu Tek Kullanımlık Olarak Düzeltme http://msdn.microsoft.com/en-us/library/yh598w02.aspx


tam olarak bu değil, ama yeterince yakın. kesin fark önemli değil.
Bryan

@Bryan alamadım, lütfen tam farktan bahsedebilir misiniz, bize daha fazla yalın yardımcı olabilir :-)
mohits00691

Vay, bu uzun zaman önce yapılmış bir yorum oldu :) Görünüşe göre ben bu yorumu yaptıktan sonraki gün bir düzenleme varmış gibi görünüyor. Düşündüğüm fark bu.
Bryan

@Bryan Evet, yorumunuzu yaptıktan sonra düzeltmeyi yaptım.
Ryan Pedersen

17

İşte benim Şablonum. Bir SQL sunucusundan veri seçmek için ihtiyacınız olan her şey. Bağlantı kapalı ve bertaraf edilmiş, bağlantı ve yürütmede hatalar var.

string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = @"
    SELECT TOP 1 Person
    FROM CorporateOffice
    WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
    ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
    using (SqlCommand comm = new SqlCommand(selectStatement, conn))
    {
        try
        {
            conn.Open();
            using (SqlDataReader dr = comm.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Console.WriteLine(dr["Person"].ToString());
                    }
                }
                else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
            }
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
        if (conn.State == System.Data.ConnectionState.Open) conn.Close();
    }
}

* Revize: 2015-11-09 *
NickG tarafından önerildiği gibi; Çok fazla diş teli sizi rahatsız ediyorsa, bu şekilde biçimlendirin ...

using (SqlConnection conn = new SqlConnection(connString))
   using (SqlCommand comm = new SqlCommand(selectStatement, conn))
   {
      try
      {
         conn.Open();
         using (SqlDataReader dr = comm.ExecuteReader())
            if (dr.HasRows)
               while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
            else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
      }
      catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
      if (conn.State == System.Data.ConnectionState.Open) conn.Close();
   }

Daha sonra, EA veya DayBreak oyunları için çalışıyorsanız, sadece herhangi bir satır sonundan vazgeçebilirsiniz, çünkü bunlar sadece geri dönüp kodunuza daha sonra bakmak zorunda olan ve gerçekten kimin umurunda? Haklı mıyım? 23 yerine 1 satır demek daha iyi bir programcı olduğum anlamına geliyor, değil mi?

using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }

Vay be ... Tamam. Bunu sistemimden çıkardım ve bir süre kendimi eğlendiriyorum. Sürdürmek.


6
Ek parantez olmadan ifadeleri kullanarak yığınlayabileceğinizi biliyor muydunuz? Son
küme

Evet efendim. Teşekkür ederim. Farkındayım ama kodumun çok fazla kısa yol kullanmadan neler olduğunu tam olarak göstermesini istedim. Yine de son okuyucu eklemek için iyi bir not.
ShaneLS

conn.Close();Sonunda neden kullanıyorsun ? Does not usingaçıklamada bertaraf yoluyla sizin için bunu?
Fredrick Gauss

Şimdi olduğuna inanıyorum (.net 3.5'ten beri). Erken .net 2.0 ile bana belli değildi bu yüzden sadece kontrol etmek ve kapatmak için bir alışkanlık yaptı.
ShaneLS

1
"23 yerine 1 satır demek daha iyi bir programcı olduğum anlamına geliyor, değil mi?" Senden hoşlanıyorum :-D
Philipp Müller

5

Kullanım kapsamından çıktığınızda imha basitçe çağrılır. "Kullanmanın" amacı, geliştiricilere kaynakların elden çıkarılmasını sağlamak için garantili bir yol sunmaktır.

Gönderen MSDN :

Using ifadesinin sonuna ulaşıldığında veya bir istisna atıldığında ve kontrol deyimin bitiminden önce deyim bloğundan ayrıldığında bir using ifadesinden çıkılabilir.


5

Usingtahsis edilen nesnenin etrafında bir deneme / son olarak oluşturur ve sizi çağırır Dispose().

Deneme / sonlandırma bloğunu manuel olarak oluşturma ve arama zahmetinden kurtarır Dispose()


3

İlk örneğinizde, C # derleyicisi using deyimini şu şekilde çevirir:

SqlConnection connection = new SqlConnection(connectionString));

try
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}
finally
{
    connection.Dispose();
}

Son olarak, bir işlev dönmeden önce deyimler her zaman çağrılır ve böylece bağlantı her zaman kapatılır / atılır.

Yani, ikinci örneğinizde kod aşağıdakilere derlenecektir:

try
{
    try
    {
        connection.Open();

        string storedProc = "GetData";
        SqlCommand command = new SqlCommand(storedProc, connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

        return (byte[])command.ExecuteScalar();
    }
    finally
    {
        connection.Dispose();
    }
}
catch (Exception)
{
}

İstisna, son açıklamada yakalanacak ve bağlantı kapanacaktır. Dış yakalama maddesi tarafından istisna görülmez.


1
çok iyi örnekler dostum, ama son yorumunuza katılmıyorum, eğer bir kullanım bloğunda bir istisna meydana gelirse, herhangi bir dış yakalamada sorunsuz bir şekilde yakalanır, aslında bir try / catch bloğu içinde 2 blok kullanarak yazarak test ettim , ve sürpriz, iç ikinci blok kullanarak gelen istisna hata mesajı aldım.
WhySoSerious

1

İki yazdım kullanarak bir iç ifadeleri deneme / yakalama bloğu ve bunu iç içine yerleştirilen eğer istisna aynı şekilde yakalandı ediliyordu görebiliyordu kullanarak sadece ShaneLS olarak açıklamaya örnek .

     try
     {
       using (var con = new SqlConnection(@"Data Source=..."))
       {
         var cad = "INSERT INTO table VALUES (@r1,@r2,@r3)";

         using (var insertCommand = new SqlCommand(cad, con))
         {
           insertCommand.Parameters.AddWithValue("@r1", atxt);
           insertCommand.Parameters.AddWithValue("@r2", btxt);
           insertCommand.Parameters.AddWithValue("@r3", ctxt);
           con.Open();
           insertCommand.ExecuteNonQuery();
         }
       }
     }
     catch (Exception ex)
     {
       MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }

Deneme / yakalama nerede olursa olsun , istisna sorunsuz bir şekilde yakalanacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.