Можно ли заменить выражение using на фигурные скобки? - PullRequest
6 голосов
/ 03 сентября 2010

Я использую оператор использования для SqlConnection. Это хорошо для производительности, потому что заставляет вызывать Dispose (), который просто освобождает соединение с пулом раньше.

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

   using (SqlConnection connection = new SqlConnection(connectionString))
   {
       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
   }

Мне было интересно, смогу ли я заменить использование и сделать что-то вроде этого:

 {
       SqlConnection connection = new SqlConnection(connectionString);

       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
 }

SqlConnection не будет доступен после последней } скобки. Будет ли Dispose () вызываться немедленно, когда объект выходит из области видимости?

Ответы [ 7 ]

13 голосов
/ 03 сентября 2010

Нет, во втором примере все не будет автоматически очищено (фактически, с вашим кодом вы оставите несколько открытых соединений открытыми).

Мало того, вы теряете автоматическую очистку в случае возникновения исключений внутри блока using.Помните, что блок using разлагается на:

SqlConnection connection = new SqlConnection(connectionString);
try
{
    connection.Open();
    // Do work
}
finally
{
    connection.Dispose();
}

Если вы действительно используете разные соединения и каждое соединение располагается в конце блока, я бы использовал несколько блоков:

using(SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    // Do Work
}

// First connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString2))
{
    // Do More Work
}

// Second connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString3))
{
    // Do More Work
}

// Last connection is dipsosed
8 голосов
/ 03 сентября 2010

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

Вы заметитечто в операторе using можно использовать только те объекты, которые реализуют IDisposable, что обеспечивает возможность вызова Dispose.

Как в этой статье объясняется,компилятор преобразует это:

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();

}

В это:

MyResource myRes= new MyResource();
try
{
    myRes.DoSomething();
}
finally
{
    if (myRes!= null)
        ((IDisposable)myRes).Dispose();
}

Итак, если вы не продублируете эту структуру, вы не получите такое же поведение.

ВКроме того, повторное использование переменной, как в вашем примере, является плохой практикой.Кто-то, кто читает код, может подумать, что он смотрит на соединение 1, когда на самом деле смотрит на 2 или 3. Это может привести к путанице и вызвать всевозможные проблемы в будущем.

3 голосов
/ 03 сентября 2010
using(foo)
{
  // stuff
}

... немного сахара, что переводится как:

try
{
  // stuff
}
finally
{
  foo.Dispose()
}

Принимая во внимание:

{
  // stuff
}

... не переводится ни во что. Это просто:

{
  // stuff
}

: D

Изменить: Пожалуйста, не разрушайте форматирование при редактировании: (

3 голосов
/ 03 сентября 2010

Нет, он не будет вызываться после закрывающей фигурной скобки. Вам нужно вызвать его вручную или использовать оператор using.

Если вы не выполните удаление, оно будет выполнено при вызове финализации. И вот у вас 2 проблемы

  • Выполнение метода Finalize дорого обходится производительности. Если ваш метод Dispose уже выполнил работу по очистке объекта, сборщику мусора не обязательно вызывать метод Finalize объекта (если он хорошо реализован, метод Dispose должен вызывать метод SuppressFinalize для объекта, который он удаляет). ). (MSDN)
  • Вы не управляете моментом, когда финализация вызывается автоматически и не может быть выполнена (например, из-за сбоя).
3 голосов
/ 03 сентября 2010

Нет, использование создает некоторые специфические конструкции очистки, которые вы не получите, используя только фигурные скобки.

Если вы используете Reflector и смотрите на IL, в концеusing block для своей цели:

    L_0006: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)
L_000b: stloc.0 
L_000c: nop 
L_000d: nop 
L_000e: leave.s L_0020
L_0010: ldloc.0 
L_0011: ldnull 
L_0012: ceq 
L_0014: stloc.1 
L_0015: ldloc.1 
L_0016: brtrue.s L_001f
L_0018: ldloc.0 
**L_0019: callvirt instance void [mscorlib]System.IDisposable::Dispose()**
L_001e: nop 
L_001f: endfinally 

Это объясняет, почему вы не можете создать новое соединение внутри блока using и присвоить его переменной - из-за этого исходная ссылка будет висеть и не располагаться.

2 голосов
/ 03 сентября 2010

Нет, вы не можете этого сделать. По крайней мере, в C #.

Но вы можете создавать различные одноразовые объекты внутри одного оператора using:

   using (SqlConnection connection1 = new SqlConnection(connectionString1),
          connection2 = new SqlConnection(connectionString2),
          connection3 = new SqlConnection(connectionString3))
   {
       connection1.Open();
       //...
       connection2.Open();
       //...
       connection3.Open();
   }

C ++ / CLI, вы можете использовать свои одноразовые классы в стекоподобной структуре:

void MyClass::Foo()
{

{
  SqlConnection connection(connectionString);
  //connection still allocated on the managed heap
  connection.Open();
  ...
  //connection will be automatically disposed 
  //when the object gets out of scope
} 


{
  SqlConnection connection(connectionString2);
  connection2.Open();
  ...
}

}
1 голос
/ 06 сентября 2010

Сначала я тоже так думал ... но, очевидно, когда блок using заканчивается, для вашего объекта вызывается .Dispose(), что отличается от выхода объекта из области видимости. Поскольку C # - это язык для сборки мусора, может пройти некоторое время, прежде чем ваш объект действительно будет очищен. Блок using обеспечивает его немедленное удаление независимо от каких-либо исключений.

...