关于资源密集型操作的最佳实践(例如打开数据库连接)的共识似乎是使用Using
块,因为Using
阻止"guarantees disposal of the resource... even in the case of an unhandled exception."。
以下是我发现的大部分例子:
Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String)
Using connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(sql, connection)
command.Connection.Open()
command.ExecuteNonQuery()
End Using
End Sub
但是允许嵌套的Using
块,我偶尔(但很少)看到上面写的:
Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String)
Using connection As New SqlConnection(connectionString)
Using command As New SqlCommand(sql, connection)
command.Connection.Open()
command.ExecuteNonQuery()
End Using
End Using
End Sub
我的问题:多个嵌套Using
块有什么好处吗?或者单个Using块是否已经保证它所包含的所有资源都将被处理?
(注意:我的代码是在VB.NET中,但同样的问题适用于C#。)
答案 0 :(得分:9)
使用块“保证资源的处理......即使在未处理的异常情况下也是如此。”
用一粒盐来保证“保证”。许多事情可以阻止资源的处置。如果using块包含无限循环怎么办?或者块抛出异常,堆栈上较高的恶意异常过滤器进入无限循环并且永远不会将控制返回到与using语句关联的finally块?或者块调用Environment.FailFast?有许多东西可以阻止处理的进行。 永远不要编写依赖于处置的程序。处理礼貌,将稀缺资源返回池中以供其他人使用。
此外,让我确保这一点很明确:真正未处理的异常是C#中实现定义的行为。 using
块的finally子句用于处理在使用块中抛出异常然后在其他地方处理的情况,而不是处理在其中抛出异常的情况块和从不处理。如果发生这种情况,那么完全取决于实施以确定会发生什么; C#语言对抛出永远不会处理的异常的程序的行为总共做出了零承诺。资源可能会被处置。他们可能不会。你在一座即将被拆除的建筑物里;你真的想花点时间洗碗并把它们整齐地拿走吗?
多个嵌套的Using块有什么好处吗?
是
单个Using块是否已经保证它所包含的所有资源都将被处理?
没有。仅清除using语句实际提到的资源。这就是你筑巢的原因。
在某些情况下,技术上你没有必要,因为内部人员负责释放与外部资源相同的资源。但是使用块来嵌套并不会造成任何伤害,这使读者清楚地知道发生了什么。这里的最佳实践是为每个要清理的资源使用一个using语句。
答案 1 :(得分:6)
嵌套using
块绝对有用:单个块仅在其自己的变量上调用Dispose
,而不在可能在同一块内打开的其他变量上调用IDisposable
。这就是为什么要在程序中的已定义点清理的每个变量(应该是实现using
的每个变量类型)都需要自己的{{1}}块。
答案 2 :(得分:3)
Using
语句将处理在Using
行内声明的变量
它对块中其他地方声明的变量没有影响。
您应该始终对每个一次性变量使用Using
语句。
答案 3 :(得分:1)
嵌套的using
语句非常有用。但是,许多程序员不认为SqlCommand
对象需要资源清理。即,资源是连接,而不是命令。
ADDED
SqlCommand没有Close()方法,因此即使SqlCommand具有Dispose()方法,缺少Close()方法也表示确实存在“无法关闭/释放”。一次性实例将始终最终处置。很难找到一些权威而没有挖掘来源,但当在this article询问MS家伙被问到究竟是什么时,他说“实际上不是很多......”然后继续建议使用USING条款。 SqlCommand(),所以我正确回答了问题,但最初避免了它背后的模糊性。
答案 4 :(得分:1)
所有其他答案都是正确的。我还要补充一点。
如果对象的类型相同,则c#编译器提供了一种在单using
语句内联中使用多个对象的方法(合成糖)。
C#版
using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream())
{
}
Vb.Net版
Using ms1 = New MemoryStream(), ms2 = New MemoryStream()
End Using
这将同时处理MemoryStream
s