A confusing fact about using statement

来源:互联网 发布:个人所得税报税软件 编辑:程序博客网 时间:2024/05/22 12:47

A confusing fact about using statement

Using语句提供简洁的语法来保证资源的回收,然而并不是所有的人都懂得using语句的实现。
在写篇Blog之前,我在Google上Search一下,发现了如下的文章:
http://www.codeproject.com/csharp/TinguUsingStatement.asp
不幸的是这片文章中有一个严重的错误。
在往下读之前,请先看看下面的Code有什么问题:

RegistryKey typeNameKey = null;
 using (typeNameKey) {
  typeNameKey = Registry.ClassesRoot.CreateSubKey(".ABCD");
  typeNameKey.SetValue("", "Test");
 }
// continue to do some work

如果执行这段代码,你会发现在Using Block结束后RegistryKey没有被回收(Dispose)
为什么? 让我们看看IL Code:

  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  stloc.1
  .try
  {
    IL_0004:  ldsfld     class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::ClassesRoot
    IL_0009:  ldstr      ".ABCD"
    IL_000e:  callvirt   instance class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.RegistryKey::CreateSubKey(string)
    IL_0013:  stloc.0
    IL_0014:  ldloc.0
    IL_0015:  ldstr      ""
    IL_001a:  ldstr      "Test"
    IL_001f:  callvirt   instance void [mscorlib]Microsoft.Win32.RegistryKey:SetValue(string,
                                                                                       object)
    IL_0024:  leave.s    IL_0030
  }  // end .try
  finally
  {
    IL_0026:  ldloc.1
    IL_0027:  brfalse.s  IL_002f
    IL_0029:  ldloc.1
    IL_002a:  callvirt   instance void [mscorlib]System.IDisposable:Dispose()
    IL_002f:  endfinally
  }  // end handler

注意黑体部分,在finally block中回收的是using block中的代码执行前typeNameKey的值。
如果该值为空则直接跳出finally block.
所以在使用using语句时要在using语句中初始化变量。正确的代码如下:
using (RegistryKey typeNameKey = Registry.ClassesRoot.CreateSubKey(".ABCD")) {
    typeNameKey.SetValue("", "Test");
}
同时注意在using block要避免改变using语句中所使用的变量的值。

 

  2004年4月19日 6:27

Details at http://blog.joycode.com/gangp/archive/2004/04/19/19852.aspx