[C#] “사용”블록에서 SqlConnection이 반환 또는 예외로 닫혔습니까?

첫 번째 질문 :
내가 가지고 있다고

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();
}

연결이 닫혔습니까? 기술적 }으로 우리는 return이전 과 다름 없이 끝까지 도달하지 않기 때문입니다.

두번째 질문 :
이번에는 :

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*/ }

이제 어딘가에 try오류가 발생하면 오류가 발생합니다. 연결이 여전히 닫혀 있습니까? 다시, 우리는 코드의 나머지 코드를 건너 뛰고 명령문 try으로 직접 이동 catch합니다.

using작동 방식에 너무 선형 적으로 생각하고 있습니까? 즉 Dispose(), 우리가 using범위를 벗어날 때 단순히 호출 됩니까 ?



답변

  1. 예.

어느 쪽이든, 사용 블록이 종료되면 (성공적으로 완료되거나 오류로 인해) 닫힙니다.

비록 나중에 지원할 새로운 유지 보수 프로그래머조차도 앞으로 일어날 일을 훨씬 쉽게 알 수 있기 때문에 이렇게 구성하는 것이 더 좋을 것이라고 생각합니다 .

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*/ 
    }
}


답변

두 질문에 모두 그렇습니다. using 문은 try / finally 블록으로 컴파일됩니다.

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

와 같다

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

편집 : 일회용 캐스트 캐스트
http://msdn.microsoft.com/en-us/library/yh598w02.aspx


답변

여기 내 템플릿이 있습니다. SQL 서버에서 데이터를 선택하는 데 필요한 모든 것. 연결이 닫히고 삭제되고 연결 및 실행 오류가 발생합니다.

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();
    }
}

* 개정 : 2015-11-09 *
NickG가 제안한대로; 너무 많은 괄호로 인해 성가신 경우 다음과 같이 포맷하십시오.

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();
   }

EA 나 DayBreak 게임을 위해 일한다면 나중에 줄 바꿈을 잊어 버릴 수 있습니다. 내가 맞아? 23이 아닌 1 줄은 내가 더 나은 프로그래머라는 것을 의미합니다.

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(); }

휴 … 좋아. 나는 그것을 내 시스템에서 꺼내어 잠시 동안 나 자신을 즐겁게 해왔다. 계속하십시오.


답변

Dispose는 사용 범위를 벗어날 때 간단히 호출됩니다. “사용”의 목적은 개발자가 리소스를 폐기 할 수있는 보장 된 방법을 제공하는 것입니다.

에서 MSDN :

using 문 끝에 도달하거나 예외가 발생하여 명령문이 종료되기 전에 제어가 문 블록을 벗어나면 using 문을 종료 할 수 있습니다.


답변

Using할당되는 객체 주위에 try / finally를 생성하고 호출 Dispose()합니다.

try / finally 블록을 수동으로 만들고 호출하는 번거 로움을 덜어줍니다. Dispose()


답변

첫 번째 예에서 C # 컴파일러는 실제로 using 문을 다음으로 변환합니다.

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();
}

마지막으로 함수가 리턴되기 전에 명령문이 항상 호출되므로 연결이 항상 닫히거나 삭제됩니다.

따라서 두 번째 예제에서 코드는 다음과 같이 컴파일됩니다.

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)
{
}

finally 문에서 예외가 발생하고 연결이 닫힙니다. 외부 catch 절에서는 예외를 볼 수 없습니다.


답변

try / catch 블록 안에 두 개의 using 작성했는데 ShaneLS example 과 같이 내부 using 문에 예외가있는 경우 예외가 같은 방식으로 잡히는 것을 볼 수 있습니다 .

     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);
     }

이다 상관없이 시도 / 캐치 배치는, 예외가 문제없이 잡힐 것입니다.