4

对资源密集型操作(例如打开数据库连接)的最佳实践的共识似乎是使用Using块,因为Using“保证资源的处置......即使在未处理的异常的情况下”。.

以下是我发现的大多数示例的编写方式:

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#。)

4

5 回答 5

10

using 块“保证资源的处置......即使在未处理的异常的情况下。”

对“保证”持保留态度。许多事情可以阻止资源的处置。如果 using 块包含无限循环怎么办?或者块抛出异常,堆栈上更高的恶意异常过滤器进入无限循环并且永远不会将控制权返回给与 using 语句关联的 finally 块?还是块调用 Environment.FailFast?有很多很多事情可以阻止处置的进行。 永远不要编写依赖处置来确保其正确性的程序。处置是出于礼貌,将稀缺的资源归还给池中供他人使用。

此外,让我确保这一点很清楚:真正未处理的异常是 C# 中实现定义的行为。块的usingfinally 子句是用来处理在 using 块内抛出异常然后在其他地方处理的情况,而不是处理在块内抛出异常并且从不处理的情况处理。如果发生这种情况,则完全由实施来确定会发生什么;对于抛出从未处理过的异常的程序的行为,C# 语言总共做出了零承诺。资源可能会被处理掉。他们可能不会。你在一座即将被意外拆除的建筑物中;你真的想花时间洗碗并把它们整齐地收起来吗?

多个嵌套的 Using 块有什么好处吗?

是的。

单个 Using 块是否已经保证它包含的所有资源都将被释放?

不会。只清理 using 语句实际提及的资源。这就是你嵌套它们的原因。

在某些情况下,从技术上讲,您不必这样做,因为内部负责释放与外部相同的资源。但是使用块嵌套并没有什么坏处,它让读者很清楚发生了什么。此处的最佳做法是为要清理的每个资源使用一个 using 语句。

于 2013-10-04T18:30:25.703 回答
7

嵌套using块绝对有用:单个块只会调用Dispose它自己的变量,而不是可能在同一块内打开的其他变量。这就是为什么要在程序中定义的点清理的每个变量(应该是实现类型的每个变量IDisposable)都需要自己的using块。

于 2013-10-04T18:25:49.413 回答
3

Using语句将处理Using行内声明的变量。
它对块中其他地方声明的变量没有影响。

您应该始终Using为每个一次性变量使用一个语句。

于 2013-10-04T18:25:09.283 回答
1

嵌套using语句非常有用。然而,许多程序员并不认为SqlCommand对象需要进行资源清理。即,资源是连接,而不是命令。

添加

SqlCommand 没有 Close() 方法,因此即使 SqlCommand 有 Dispose() 方法,但缺少 Close() 方法表明确实“没有什么可以关闭/释放”。可处置的实例最终将始终被处置。如果不挖掘源代码就很难找到权威的东西,但是当在这篇文章中被问到 MS 的人被问到它到底做了什么时,他说“实际上不是很多......”并继续为 SqlCommand() 建议一个 USING 子句,所以我正确地回答了这个问题,但最初避免了它背后的模糊性。

于 2013-10-04T18:28:46.203 回答
1

所有其他答案都是正确的。我再补充一点。

如果对象属于同一类型,c# 编译器提供了一种方法(语法糖)在单个using语句内联中使用多个对象。

C#版本

using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream())
{

}

vb.net版

Using ms1 = New MemoryStream(), ms2 = New MemoryStream()

End Using

这将同时处理MemoryStreams

于 2013-10-04T18:54:28.170 回答