嵌套的 Using 语句有用

本文关键字:有用 语句 Using 嵌套 | 更新日期: 2023-09-27 18:34:08

关于资源密集型操作(例如打开数据库连接(的最佳实践的共识似乎是使用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#。

嵌套的 Using 语句有用

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

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

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

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

是的。

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

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

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

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

Using 语句将释放在Using行中声明的变量。
它对块中其他位置声明的变量没有影响。

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

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

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

C# 版本

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

Vb.Net 版本

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

这将处理两个MemoryStream

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

添加

SqlCommand 没有 Close(( 方法,

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