Поместит ли "использование" выражение вокруг DataReader закроет его?
Обычно я пишу свой код DataReader
следующим образом:
try
{
dr = cmd.ExecuteReader(CommandBehavior.SingleResult);
while (dr.Read())
{
// Do stuff
}
}
finally
{
if (dr != null) { dr.Close(); }
}
Безопасно ли заменить try
и finally
блоком using
вокруг создания DataReader
? Причина в том, что во всех примерах Microsoft, которые я видел, они используют использование для соединения, но всегда явно вызывают Close()
на DataReader
.
Вот пример из
Извлечение данных с помощью DataReader (ADO.NET):
static void HasRows(SqlConnection connection)
{
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM Categories;",
connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
Ответы
Ответ 1
Да. using
вызывает Dispose. Вызов Dispose на SqlDataReader закрывает его.
Это psuedo-код SqlDataReader, полученный из Reflector:
public void Dispose()
{
this.Close();
}
public override void Close()
{
if( !IsClosed )
CloseInternal(true);
}
private void CloseInternal(bool closeReader)
{
try
{
// Do some stuff to close the reader itself
}
catch(Exception ex)
{
this.Connection.Abort();
throw;
}
if( this.Connection != null && CommandBehavior.CloseConnection == true )
{
this.Connection.Close();
}
}
Ответ 2
Как правило, using()
вызывает Dispose()
и вызывает по очереди close()
.
В случае DataReader, Close вызывается только тогда, когда установлен CommandBehavior.CloseConnection
(см. комментарии к этой статье http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp-disposal-of-a-datareader.aspx).
EDIT: В этой статье говорится что-то интересное:
Метод Close() на SqlDataReader вызывает InternalClose() метод, который не вызывает Dispose. Обратите внимание, что ранее мы заявляли Правильный способ сделать это - ваш закрытый вызов. Сделать это еще больше запутывает Dispose() метод фактически вызывает Close() метод, поэтому для этого объекта порядок наоборот.
Ответ 3
Из того, что я могу вспомнить, если исключение возникает в блоке Using, то метод Dispose все еще вызывает объект. Обычно у меня есть оператор Using для всех одноразовых объектов без Try..Catch.
EDIT: Забыл сказать, что для некоторых объектов вызов Dispose в свою очередь вызовет Close для этого объекта.
Ответ 4
В отличие от примера здесь, моя практика заключалась в использовании блока использования для соединения, команды и читателя. Обратите внимание, что вы можете складывать вложенные блоки, чтобы снизить стоимость отступа.
static void HasRows(SqlConnection connection)
{
using (connection)
using (SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM Categories;",
connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
}