使用use来处理嵌套对象

如果我有这样的嵌套对象的代码,我是否需要使用嵌套的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(); } } 

是。 你可以像这样清理一下

 using (SqlConnection conn = new SqlConnection(sqlConnString)) using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand()) { // code here } 

但是你仍然想要为每个IDisposable对象使用。

编辑:考虑这个使用内部using语句的示例。

 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()) { } 

当执行离开块(实际上是 )时,编译的代码执行对每个对象的Dispose()方法的调用。

您应该同时调用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,但在这种情况下,我认为这不太可能。

您可以省略围绕SqlCommand的使用。 GC最终将为您清理它。 但是,我强烈建议你不要这样做。 我会解释原因。

SqlCommand间接inheritance自System.ComponentModel.Component ,因此它inheritance了其Finalizer方法。 不在SqlCommand上调用dispose将确保命令在超出范围后至少提升一代(.NET垃圾收集器是世代gc )。 例如:当命令在gen 1中时,它将继续到gen 2.可终结对象在内存中保留更长时间以确保终结器可以安全运行。 但是不仅命令本身保存在内存中,而且它引用的所有对象都与它一起运行。 它将引用的对象是SqlConnectionSqlParameter对象列表,可能大的CommandText字符串以及它引用的许多其他内部对象。 只有在收集了这一代时才能删除该内存,但生成的次数越多,扫描的次数就越少。

因此,不调用会给终结器线程带来额外的内存压力和额外的工作。

当.NET无法分配新内存时,CLR将强制所有代的垃圾收集。 在此之后,运行时通常会有足够的空间来分配新对象。 但是,当内存中有很多对象仍然必须被提升为下一代(因为它们可以最终化,或者被可终结对象引用)时,这种强制收集发生时,CLR可能无法释放足够的记忆力。 OutOfMemoryException将是此结果。

我必须承认,我从未见过这种情况,因为开发人员并没有只处理他们的SqlCommand对象。 但是,由于没有正确处理对象,我在生产系统中看到了很多OOM。

我希望这给出了关于GC如何工作的一些背景知识以及未正确处理(可最终化)对象的风险。 我总是处理所有一次性物品。 虽然reflection器中的外观可以certificate这不一定适用于某种类型,但这种编程会导致代码的可维护性降低,并使代码依赖于类型的内部行为(此行为可能在将来发生变化)。

要回答你的问题,是的,你可以做到这一点。

由于SqlCommand对象受外括号限制,因此当执行超出块时,GC将收集它。

其他答案也没关系,但他们没有完全回答你的问题:)