using语句可以用花括号替换吗?

时间:2010-09-03 12:49:45

标签: c# scope using-statement sqlconnection

我使用SqlConnection的using语句。它对性能有好处,因为强制调用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 个答案:

答案 0 :(得分:13)

不,在第二个示例中,事情不会自动清理(实际上,使用您拥有的代码,您将保持几个连接处于打开状态)。

不仅如此,如果在using块内抛出异常,您将失去自动清理功能。请记住,using块分解为:

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

如果你真的使用不同的连接,并且每个连接在块的末尾都是Disposed,我会使用几个使用块:

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

答案 1 :(得分:8)

using语句是语法糖,在Dispose内初始化的对象上调用(),因此您不能像在示例中那样简单地替换它。

您会注意到,using语句中可以使用的唯一对象是实现IDisposable的对象,这可以确保可以调用Dispose

正如this文章解释的那样,编译器将对此进行转换:

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

}

对此:

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

因此,除非您复制此结构,否则您将无法获得相同的行为。

此外 - 以你在你的例子中的方式重用变量是不好的做法。读取代码的人可能会认为他们正在查看连接1,而实际上他们正在查看2或3.最终可能会造成混乱并导致各种问题。

答案 2 :(得分:3)

不,使用创建一些特定的清理构造,只有大括号才能获得。

如果您使用Reflector并查看IL,则会在using块的末尾为其目标添加一个Dispose调用:

    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块中创建一个新连接并将其分配给变量 - 这样做会使原始引用挂起并且不会被遮挡。

答案 3 :(得分:3)

不,在结束大括号后不会调用它。您需要手动调用它或使用using语句。

如果你没有执行dispose那么它将在调用finalize时执行。在这里你有2个问题

  • 执行Finalize方法的性能代价很高。如果你的Dispose方法已经完成了清理对象的工作,那么垃圾收集器就没有必要调用对象的Finalize方法(如果它已经很好地实现了,Dispose方法应该为它正在处理的对象调用SuppressFinalize方法) )。 (MSDN)
  • 您无法控制自动调用finalize并且无法执行的时刻(例如因为崩溃)。

答案 4 :(得分:3)

using(foo)
{
  // stuff
}

...有点糖转化为:

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

鉴于:

{
  // stuff
}

......不会转化为任何东西。它只是:

{
  // stuff
}

:d

编辑:编辑时请不要破坏格式:(

答案 5 :(得分:2)

不,你不能这样做。至少在C#中。

但是你可以在一个使用语句中创建不同的一次性对象:

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

C ++ / CLI你可以在类似堆栈的faision中使用你的一次性类:

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

}

答案 6 :(得分:1)

我一开始也这么想......但显然当使用块结束时,会在您的对象上调用.Dispose(),这与让对象超出范围不同。因为C#是一种垃圾收集语言,所以在实际清理对象之前可能需要一些时间。 using块确保立即处理它,并且无论是否有任何例外。