我一直在深入研究微软的代码分析,偶然发现了一些有趣的事情。.NET似乎会根据调用方式使用两种不同类型的Dispose方法。请看以下两个选项:
public void SqlConnectionUsing()
{
using (SqlConnection connection = new SqlConnection())
{
}
}
public void SqlConnectionFinally()
{
SqlConnection connection = new SqlConnection();
try
{
}
finally
{
connection.Dispose();
}
}
两个选项在编译时被翻译为完全相同的内容。使用语句变成了一个try-finally语句,try块中包含对Dispose方法的调用,finally块中也包含对Dispose方法的调用。
我说“一个”Dispose方法,因为Dispose方法的种类取决于您编写代码的方式。
当选择“using语句”时,将调用
callvirt instance void [mscorlib]System.IDisposable::Dispose()
(这是确切的IL代码行)。而手动选择try-finally选项,则Dispose语句更改为:
callvirt instance void [System]System.ComponentModel.Component::Dispose()
。为什么会有调用不同dispose函数的区别?
如果需要,我可以添加整个IL代码。
using
附带了null
检查。 - westonusing
会自动调用Dispose;不进行空值检查可能会导致异常。 - MatthijsIDisposable
实现者注意的陷阱,请参见Using clause fails to call Dispose?。 - groverboy((IDisposable)connection).Dispose()
并不完全等价,而是CallDispose(connection)
,假设void CallDispose<T>(T it) where T:IDisposable { if (it != null) it.Dispose(); }
。如果it
是一个带有(可能是无用的)IDisposable
实现的结构体,则前者将对其进行装箱,但后者不会。请注意,由于C#会处理using
语句中参数的副本,因此即使在可以提高效率的情况下使用具有非平凡Dispose
方法的结构体也是不可能有用的。 - supercat