我使用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()会立即被调用吗?
答案 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个问题
答案 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
块确保立即处理它,并且无论是否有任何例外。