仅在 using 语句范围内创建和使用时的对象生命周期

Object lifetime when created and used only in the scope of a using statement

当一个对象仅在 using 语句的范围内创建和使用时,它是否会在其封闭的 IDisposable 实例的处置过程中被处置?如果不是,为什么不是?

例如,在使用 Dapper 时,我经常在 SqlConnection 的范围内创建一个匿名对象,给人的印象是它会被更快地处理掉——但我最近读到的内容恰恰相反。

using (var connection = new SqlConnection("Connection String"))
{
    var parameters = new
    { 
        Message = "Hello world!"
    };

    connection.Execute("INSERT INTO...", parameters);
}

您的 using 语句本质上等同于:

 var connection = new SqlConnection("Connection String");

 try
 {
     var parameters = new
     { 
         Message = "Hello world!"
     };
 }
 finally
 {
     if (connection != null)
     {
         ((IDisposable)connection).Dispose();
     }
 }

如您所见,在 try 块内创建的任何其他 IDisposable 实例没有理由自动为您处理。如果您确实需要确保处理其他对象,那么只需嵌套 using 语句:

using (var connection = new SqlConnection("Connection String"))
{
     using (var otherDisposableObject = new ....)
     {
     } //otherDisposableObject disposed
} //connection disposed

如果过多的嵌套妨碍了可读性,那么你可以简单地编写如下的 using 语句:

using (var connection = new SqlConnection("Connection String"))
using (var otherDisposableObject = new ....)
using (var anotherDisposableObject = new ....)
using (var andAnotherDisposableObject = new ....)
{
} //andAnotherDisposableObject, anotherDisposableObject, otherDisposableObject and connection all disposed

请记住,您似乎将垃圾收集与处置对象混为一谈。在您的示例中,一旦执行退出 using 语句,parameters 就可以进行垃圾回收,因为没有对其的实时引用。

垃圾收集达到 GC 时,很可能永远不会,这取决于您的应用程序的内存压力。 如果它被垃圾收集,那么它会被标记为对终结有效并且对象的终结器将被调度到运行 .同样,是否以及何时发生完全取决于 GC

最后,如果对象的IDisposable模式被正确实现并且finalizer是运行 , Dispose() 将被调用(准确地说, Dispose(false) 将被调用)并且该对象将处理它可能持有的任何非托管资源(在此上下文中无法安全地处理托管资源,但它确实不会没关系,GC 最终也会照顾他们)。

参见 IDisposable Pattern for more details on how it works or even better, check out this excellent SO answer