以前看书上说Using实质是编译器生成Try{} Finally{},保证Finally始终执行。一直没太仔细想这个问题。今天写代码,碰到一段程序如下:
1 SqlDataReader Func() 2 { 3 4 using (SqlConnection conn=new SqlConnection()) 5 { 6 conn.Open(); 7 using (SqlCommand comm=new SqlCommand()) 8 { 9 //............省略若干初始化 10 SqlDataReader dr= comm.ExecuteReader(); 11 return dr; 12 } 13 14 } 15 }
本以为return了之后using就不会dispose对象了,没想到返回的SqlDataReader已经关闭连接了。于是查了查MSDN看到下面一段示例:
代码
使用using语句实际上生成的IL代码中是一个try, finally代码块,在finally代码块里释放资源。
比如这样一段代码:
using (SqlConnection conn = new SqlConnection()) { conn.Open(); throw new Exception("Exception!!");//抛出异常之后能回收SqlConnection对象的资源吗? }
IL 代码可为:
// Code size 42 (0x2a) .maxstack 2 .locals init ([0] class [System.Data]System.Data.SqlClient.SqlConnection conn, [1] bool CS$4$0000) IL_0000: nop IL_0001: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor() IL_0006: stloc.0 .try { IL_0007: nop IL_0008: ldloc.0 IL_0009: callvirt instance void [System.Data]System.Data.Common.DbConnection::Open() IL_000e: nop IL_000f: ldstr "Exception!!" IL_0014: newobj instance void [mscorlib]System.Exception::.ctor(string) IL_0019: throw } // end .try finally { IL_001a: ldloc.0 IL_001b: ldnull IL_001c: ceq IL_001e: stloc.1 IL_001f: ldloc.1 IL_0020: brtrue.s IL_0029 IL_0022: ldloc.0 IL_0023: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0028: nop IL_0029: endfinally } // end handler
可以看到调用了SqlConnection的Dispose方法释放了资源。
说明using语句不论语句块里面是否return,均会生成资源释放的代码。Try。。Finally块也一样,也是先执行完Finally,再执行try里面可能有的return;
下面的代码证实了这一点:
代码
class Program { static void Main(string[] args) { using (UsingTest ut= testFunc()) {
}
}
static UsingTest testFunc() { try{ UsingTest ut = new UsingTest(); return ut; } finally {
Console.WriteLine("finally...");
} return null;//这里的代码始终无法访问到,说明try里面的return实际上是执行完finally后立即执行的 } }
internal class UsingTest:IDisposable {
public UsingTest() { Console.WriteLine("Constructing..."); } public void Dispose() { Console.Write("Disposing....."); } }
程序输出:
"Constructing..."
"finally..."
"Disposing....."
|
请发表评论