using语句可以用大括号代替吗?

发布于 2024-09-17 18:00:59 字数 783 浏览 3 评论 0原文

我对 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() 吗?

I use the using statement for SqlConnection. It's is good for performance because forces calling Dispose() that simply releases the connection to the pool sooner.

However, I realized that object created in using cannot be redefined. I cannot do like this:

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

I was wondering if I can replace using, and do something like this:

 {
       SqlConnection connection = new SqlConnection(connectionString);

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

The SqlConnection will not be accesible after last } brace. Will be the Dispose() called immediatly when object goes out of scope?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

却一份温柔 2024-09-24 18:00:59

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

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

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

如果您确实使用不同的连接,并且每个连接在块的末尾被 Dispose of,我将使用多个 using 块:

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

No, things won't get automatically cleaned up in your second example (in fact, with the code you have, you'll leave several connections hanging open).

Not only that, but you lose the automatic cleanup in case of Exceptions being thrown inside the using block. Remember that a using block decomposes into:

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

If you're really using different connections and each connection is Disposed of at the end of the block, I would use several using blocks:

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
何以心动 2024-09-24 18:00:59

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。最终可能会非常混乱并导致各种问题。

The using statement is syntactic sugar that calls Dispose on the objects initialized within the (), so you can't simply replace it as you have in your example.

You will note that the only objects that you can use within a using statement are those that implement IDisposable, which ensures that Dispose can be called.

As this article explains, the compiler will transform this:

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

}

To this:

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

So, unless you duplicate this structure, you won't get the same behavior.

In addition - reusing a variable the way you are in your example is bad practice. Someone who reads the code may think they are looking at connection 1 when they are in fact looking at 2 or 3. Could end up very confusing and cause all kinds of problems down the road.

北风几吹夏 2024-09-24 18:00:59

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

如果不执行dispose,那么它将在调用finalize时执行。这里有两个问题:

  • 执行 Finalize 方法会降低性能。如果您的 Dispose 方法已经完成了清理对象的工作,那么垃圾收集器就没有必要调用该对象的 Finalize 方法(如果实现得很好,Dispose 方法应该为其正在处置的对象调用 SuppressFinalize 方法) )。 (MSDN)
  • 您无法控制最终确定的时刻自动调用并且无法执行(例如因为崩溃)。

No, it won't be called after the closing curly brace. You need to call it manually or use a using statement.

If you don't execute the dispose then It will be executed when the finalize is called. And here you have 2 problems

  • Executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method (if it's well implemented, a Dispose method should call the SuppressFinalize method for the object it is disposing). (MSDN)
  • You don't control the moment when the finalize is automatically called and could not be executed (because a crash for instance).
秋意浓 2024-09-24 18:00:59

不,使用创建了一些特定的清理结构,而仅使用大括号是无法获得这些结构的。

如果您使用 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 块内创建新连接并将其分配给变量 - 这样做因此会使原始参考挂起且未处理。

No, using creates some specific clean-up constructs that you won't get with just the braces.

If you use Reflector and look at the IL there's a call to Dispose added at the end of the using block for its target:

    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 

This explains why you can't create a new connection inside the using block and assign it to the variable -- doing so would leave the original reference hanging and undisposed.

风情万种。 2024-09-24 18:00:59
using(foo)
{
  // stuff
}

...是一点糖,翻译成:

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

然而:

{
  // stuff
}

...不翻译成任何东西。只是::

{
  // stuff
}

D

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

using(foo)
{
  // stuff
}

...is a bit of sugar which translates into:

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

Whereas:

{
  // stuff
}

...doesn't translate into anything. It's just:

{
  // stuff
}

:D

Edit: Please don't destroy formatting when you edit :(

好听的两个字的网名 2024-09-24 18:00:59

不,你不能这样做。至少在 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();
  ...
}

}

No, you can't do this. At least in C#.

But you can create different disposable objects inside one using statement:

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

C++/CLI you may use your disposable classes in stack-like 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();
  ...
}

}
等待我真够勒 2024-09-24 18:00:59

我一开始也这么认为......但显然当 using 块结束时,会在您的对象上调用 .Dispose() ,这与让对象超出范围不同。由于 C# 是一种垃圾收集语言,因此实际清理对象可能需要一些时间。 using 块确保它被立即处理,无论是否出现任何异常。

I thought this too at first... but apparently when the using block ends, .Dispose() is called on your object, which is different than letting the object go out of scope. Because C# is a garbage collected language, it could take time before your object is actually cleaned up. The using block ensures that it is disposed of immediately, and regardless of any exceptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文