仅在 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。
当一个对象仅在 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。