в блоке "using" 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
объем?
7 ответов:
- да
- да.
в любом случае, когда блок using выходит (либо по успешному завершению, либо по ошибке), он закрывается.
хотя я думаю, что это будет лучше чтобы организовать так, потому что гораздо легче увидеть, что произойдет, даже для нового программиста обслуживания, который будет поддерживать его позже:
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(); }
Edit: фиксация броска на одноразовый http://msdn.microsoft.com/en-us/library/yh598w02.aspx
вот мой шаблон. Все, что нужно для выбора данных из SQL server. Соединение закрывается и удаляется, а ошибки в соединении и выполнении перехватываются.
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 *
Как предложил Никг; если слишком много скобок раздражает вас, формат, как это...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 games, вы можете просто отказаться от любых разрывов линий, потому что они предназначены только для людей, которые должны прийти вернитесь и посмотрите на свой код позже, и кого это действительно волнует? Я прав? Я имею в виду, что 1 строка вместо 23 означает, что я лучший программист, верно?
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 блок, и я мог видеть, что исключение было поймано таким же образом, если оно помещено во внутренний используя заявление так же, как ShaneLS пример.
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); }
независимо от того, где try / catch размещены, исключение будет поймано без проблем.