Используя использование для избавления от вложенных объектов

Если у меня есть код с вложенными объектами как это, делают я должен использовать вложенные операторы использования, чтобы удостовериться, что от и SQLCommand и объектов SQLConnection избавляются правильно как показанный ниже, или я хорошо, если код, который инстанцирует SQLCommand, во внешнем операторе использования.

using (var conn = new SqlConnection(sqlConnString))
{
    using (var cmd = new SqlCommand())
    {
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = cmdTextHere;
        conn.Open();

        cmd.Connection = conn;
        rowsAffected = cmd.ExecuteNonQuery();
    }
}
5
задан Steven 20 April 2010 в 20:27
поделиться

4 ответа

Да. Вы можете немного очистить это

using (SqlConnection conn = new SqlConnection(sqlConnString))
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
{
   // code here
}

, но вы все равно захотите , используя для каждого IDisposable объекта.

Редактировать: Рассмотрим этот пример , а не с использованием внутреннего оператора using .

class A : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("A Disposed");
    }
}

class B : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("B Disposed");
    }
}

Код

using (A a = new A())            
{
    B b = new B();
}

В конце блока правильно размещается A. Что происходит с B? Что ж, это выходит за рамки и просто ждет сборки мусора. B.Dispose () не вызывается. С другой стороны

using (A a = new A())
using (B b = new B())
{
}

, когда выполнение выходит из блока (фактически, блоков ), скомпилированный код выполняет вызовы метода Dispose () каждого объекта.

8
ответ дан 18 December 2019 в 10:43
поделиться

Вы должны вызвать dispose для обоих, однако его будет легче прочитать, если вы просто сделаете это:

using (SqlConnection conn = new SqlConnection(sqlConnString)) 
using (SqlCommand cmd = new SqlCommand()) 
{ 
     cmd.CommandType = CommandType.Text; 
     cmd.CommandText = cmdTextHere; 
     conn.Open(); 

     cmd.Connection = conn; 
     rowsAffected = cmd.ExecuteNonQuery(); 
} 

, поскольку создается неявный блок (например, оператор if или оператор for), и поскольку using - это весь блок, вы подтяжки не нужны, и, на мой взгляд, выглядит аккуратнее. Некоторые скажут, что вы всегда должны использовать фигурные скобки, потому что слишком легко случайно добавить второй оператор и создать ошибку, но в данном случае я думаю, что это маловероятно.

4
ответ дан 18 December 2019 в 10:43
поделиться

Отвечая на ваш вопрос, да, вы можете это сделать.

Поскольку объект SqlCommand ограничен внешними фигурными скобками, он будет собран сборщиком мусора, когда выполнение выйдет за пределы блока.

Другие ответы тоже приемлемы, но они не дали точного ответа на ваш вопрос :)

0
ответ дан 18 December 2019 в 10:43
поделиться

Вы можете опустить using вокруг SqlCommand. GC в конечном итоге очистит его для вас. Однако я настоятельно рекомендую вам этого не делать. Я объясню почему.

SqlCommand косвенно наследуется от System.ComponentModel.Component, и поэтому наследует его метод Finalizer. Отсутствие вызова dispose для SqlCommand гарантирует, что команда будет перемещена по крайней мере на одно поколение после выхода из области видимости (сборщик мусора .NET является generational gc). Например: если команда была в gen 1, она перейдет в gen 2. Финализируемые объекты хранятся в памяти дольше, чтобы обеспечить безопасный запуск финализатора. Но не только сама команда хранится в памяти, но и все объекты, на которые она ссылается, переходят вместе с ней в это поколение. Объектами, на которые она ссылается, являются SqlConnection, список объектов SqlParameter, возможно, большая строка CommandText и многие другие внутренние объекты, на которые она ссылается. Эта память может быть удалена только при сборе данного поколения, но чем выше поколение, тем реже оно выкачивается.

Поэтому отказ от вызова создаст дополнительное давление на память и дополнительную работу для потока финализатора.

Когда .NET не может выделить новую память, CLR принудительно соберет мусор всех поколений. После этого в среде выполнения обычно снова появляется достаточно места для выделения новых объектов. Однако, когда эта принудительная сборка происходит, когда в памяти есть много объектов, которые все еще должны быть переведены в следующее поколение (потому что они финализируемые или на них ссылается финализируемый объект), возможно, что CLR не может освободить достаточно памяти. Результатом этого будет OutOfMemoryException.

Должен признаться, я никогда не видел, чтобы такое случалось, потому что разработчики не утилизировали только свои объекты SqlCommand. Однако я часто видел OOM в производственных системах, вызванные неправильной утилизацией объектов.

Надеюсь, это дает небольшое представление о том, как работает GC и каков риск неправильной утилизации (финализируемого) объекта. Я всегда утилизирую все одноразовые объекты. Хотя взгляд в Reflector может доказать, что это не обязательно для определенного типа, такое программирование приводит к тому, что код становится менее сопровождаемым и зависит от внутреннего поведения типа (а это поведение может измениться в будущем).

4
ответ дан 18 December 2019 в 10:43
поделиться
Другие вопросы по тегам:

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