如果我有像这样的嵌套对象的代码,我是否需要使用嵌套的using语句来确保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();
}
}
答案 0 :(得分:8)
是。你可以把它清理一下这个
using (SqlConnection conn = new SqlConnection(sqlConnString))
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
{
// code here
}
但是你仍然希望每个IDisposable对象都有一个using
。
修改:使用内部using
语句考虑 not 的示例。
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())
{
}
当执行离开块时(实际上, blocks ),编译后的代码会执行对每个对象的Dispose()方法的调用。
答案 1 :(得分:4)
您应该同时调用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语句),并且因为使用了整个块,所以你不需要大括号,在我看来它看起来更整洁。有些人会说你总是使用大括号,因为很容易意外地添加第二个语句并创建一个bug,但在这种情况下我认为这不太可能。
答案 2 :(得分:4)
您可以省略SqlCommand
周围的使用。 GC最终将为您清理它。但是,我强烈建议你不要这样做。我会解释原因。
SqlCommand
间接继承自System.ComponentModel.Component
,因此会继承其Finalizer
方法。不在SqlCommand
上调用dispose将确保命令在超出范围后至少提升一代(.NET垃圾收集器为generational gc)。例如:当命令在gen 1中时,它将继续到gen 2.可终结对象在内存中保留更长时间以确保终结器可以安全运行。但是不仅命令本身保存在内存中,而且它引用的所有对象都将它与它生成。它将引用的对象是SqlConnection
,SqlParameter
对象列表,可能很大的CommandText
字符串,以及它引用的许多其他内部对象。只有在收集该代数时才能删除该内存,但生成的次数越多,扫描的次数就越少。
因此,不调用会给终结器线程带来额外的内存压力和额外的工作。
当.NET无法分配新内存时,CLR将强制所有代的垃圾收集。在此之后,运行时通常会有足够的空间来分配新对象。但是,当内存中有很多对象仍然必须被提升到下一代(因为它们可以最终化,或者被可终结对象引用)时,这种强制收集发生时,CLR可能无法释放足够的记忆力。这将是OutOfMemoryException
的结果。
我必须承认我从未见过这种情况,因为开发人员并没有只处理他们的SqlCommand
个对象。但是,由于没有正确处理对象,我在生产系统中看到了很多OOM。
我希望这给出了一些关于GC如何工作的背景以及没有正确处理(可终结)对象的风险。我总是丢弃所有一次性物品。虽然看看Reflector可以证明这不一定适用于某种类型,但这种编程会导致代码的可维护性降低,并使代码依赖于类型的内部行为(这种行为将来可能会发生变化)。
答案 3 :(得分:0)
要回答你的问题,是的,你可以这样做。
由于SqlCommand
对象受外括号限制,因此当执行离开块时,GC将收集它。
其他答案也没问题,但他们没有完全回答你的问题:)