25

Вопрос по c#, .net, ado.net – Будет ли закрывать это выражение «использование» вокруг 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();
    }
}

@ ShadowWizard это хороший момент.

от user456814

@ Кекс не обманщик по моему мнению. Этот здесь спрашивает, еслиusing Блок закроет устройство чтения данных, другой спросит, нужно ли его закрывать. Не то же самое.

от Shadow Wizard

Возможный дубликатНужно ли вручную закрывать и утилизировать SqlDataReader?

от user456814

@ Не за качество примера кода, я подозревалгодами что он написан и поддерживается стажерами начального уровня, а не людьми, которые изначально разрабатывали классы. Такие вещи, как тусклая документация Microsoft .NET, заставляют меня с нетерпением ждатьНовое расширение документации SO.

от user456814

Как примечание, большинство примеров MS, которые я видел, либо слишком сложны, либо не используют большинство доступных языковых функций. Отчасти это потому, что они просто пролистывают пример кода из предыдущих выпусков и действительно только проверяют, что он все еще работает. Я предполагаю, что этот код не поддерживается их самыми яркими, потому что код никогда не бывает умным или эффективным.

от NotMe
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();
        }
    }
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 (), поэтому для этого объекта порядок меняется на противоположный.

1

В отличие от примераstatic void HasRows(SqlConnection connection)

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

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

Из того

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

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

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