Вопрос по c#, .net, ado.net – Будет ли закрывать это выражение «использование» вокруг DataReader?

25

Я обычно пишу свой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();
    }
}
@ Не за качество примера кода, я подозревалгодами что он написан и поддерживается стажерами начального уровня, а не людьми, которые изначально разрабатывали классы. Такие вещи, как тусклая документация Microsoft .NET, заставляют меня с нетерпением ждатьНовое расширение документации SO. user456814
Как примечание, большинство примеров MS, которые я видел, либо слишком сложны, либо не используют большинство доступных языковых функций. Отчасти это потому, что они просто пролистывают пример кода из предыдущих выпусков и действительно только проверяют, что он все еще работает. Я предполагаю, что этот код не поддерживается их самыми яркими, потому что код никогда не бывает умным или эффективным. NotMe
@ Кекс не обманщик по моему мнению. Этот здесь спрашивает, еслиusing Блок закроет устройство чтения данных, другой спросит, нужно ли его закрывать. Не то же самое. Shadow Wizard
@ ShadowWizard это хороший момент. user456814

Ваш Ответ

4   ответа
18

using звонки утилизировать. Вызов Dispose на SqlDataReader закрывает его.

Это псевдо-код SqlDataReader, полученный изрефлектор:

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

что я могу вспомнить, если исключение происходит в блоке Using, то метод Dispose по-прежнему вызывается для объекта. У меня обычно есть оператор Using для всех одноразовых объектов, без Try..Catch.

РЕДАКТИРОВАТЬ: Забыл сказать, что для некоторых объектов вызов Dispose, в свою очередь, вызовет Close для этого объекта.

1

В отличие от примераВотМоя практика заключалась в использовании блока использования для соединения, команды и считывателя. Обратите внимание, что вы можете сложить вложенные блоки, чтобы снизить стоимость отступов.

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

Как правило,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).

РЕДАКТИРОВАТЬ:Эта статья говорит что-то интересное:

Метод Close () в SqlDataReader вызывает метод InternalClose (), который не вызывает Dispose. Обратите внимание, что ранее мы указали, что правильный способ сделать это состоял в том, чтобы закрыть ваш ближайший вызов. Чтобы сделать его еще более запутанным, метод Dispose () фактически вызывает метод Close (), поэтому для этого объекта порядок меняется на противоположный.

Похожие вопросы