zoukankan      html  css  js  c++  java
  • 关于using……的一些探讨

    .NET中c#或者vb.net之所以那么吸引人,其重要原因之一就是其存在大量的“简化写法”——这些“简化写法”主要通过“语法糖”的形式存在(比如Lambda,匿名方法等……)。今天我们来探讨一下using……这个“语法糖”的本质和用法,以及一些常见的错误。

    1)using……用法:

    在C#或者是VB.NET中“using”必须和一个实现了IDisposible接口的实体类混合使用,其语法形式为:

    [C#]

    using(类名称 实体名称 = new 类名称())
    {
        //这里使用……
    }

    [VB.NET]

    Using 实体名 As New 类名称
    '这儿使用这个类实体……
    End Using

    通过MSDN的说明我们可以知道using的本质是一个try……finally:
    [C#]

    类名称 实体名称 = null;
    try
    {
      实体名称 = new 类名称();
    }
    finally
    {
      实体名称.Dispose();
    }

    [VB.NET]

    Dim 实体名称 As 类名称 = Nothing
    Try
    实体名称 = New 类名称()
    Finally
    实体名称.Dispose()
    End Try

    一般地,凡是使用using块的实体只能在using作用域中使用(即只允许在using的{……}中使用)。其实从真实情况下的try……finally……中也可以得出这样一个结论——因为无论如何,Finally必须被执行,也就是说Dispose被调用之后实体对象(内部一些托管或非托管对象实体等)已经被销毁,虽然“类实体”自身并未被回收,但是此类已经无法再使用了。

    下面在进行一下拓展:

    【例】,问以下程序运行的结果:

    [C#]

    class Fun:IDisposable
    {
       public int I{get;set;}
       public Fun()
        {
             I=1;
        }
       public void Dispose()
       {
              I=0;
       }    
    }
    
    class MainTest
    {
        static int Func()
        {
              using(Fun f = new Fun())
             {
                     return f.I;
             }
        }
        static void Main()
        {
             Console.WriteLine(Func());
        }
    }

    [VB.NET]

    Class Fun
        Implements IDisposable
        Public Property I() As Integer
            Get
                Return m_I
            End Get
            Set
                m_I = Value
            End Set
        End Property
        Private m_I As Integer
        Public Sub New()
            I = 1
        End Sub
        Public Sub Dispose()
            I = 0
        End Sub
    End Class
    
    Class MainTest
        Private Shared Function Func() As Integer
            Using f As New Fun()
                Return f.I
            End Using
        End Function
        Private Shared Sub Main()
            Console.WriteLine(Func())
        End Sub
    End Class

    粗看此题目,或许你会认为说因为Finally无论如何必须要执行,因此I从1变成了0,输出的也是0——其实不然!在using中如果使用了“return”之后,内部生成的代码略有变化(我们通过IL来证明):

    .method private hidebysig static int32  Func() cil managed
    {
      // 代码大小       36 (0x24)
      .maxstack  2
      .locals init ([0] class CSharp.Fun f,
               [1] int32 CS$1$0000,
               [2] bool CS$4$0001)
      IL_0000:  nop
      IL_0001:  newobj     instance void CSharp.Fun::.ctor()
      IL_0006:  stloc.0
      .try
      {
        IL_0007:  nop
        IL_0008:  ldloc.0
        IL_0009:  callvirt   instance int32 CSharp.Fun::get_I()
        IL_000e:  stloc.1
        IL_000f:  leave.s    IL_0021
      }  // end .try
      finally
      {
        IL_0011:  ldloc.0
        IL_0012:  ldnull
        IL_0013:  ceq
        IL_0015:  stloc.2
        IL_0016:  ldloc.2
        IL_0017:  brtrue.s   IL_0020
        IL_0019:  ldloc.0
        IL_001a:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
        IL_001f:  nop
        IL_0020:  endfinally
      }  // end handler
      IL_0021:  nop
      IL_0022:  ldloc.1
      IL_0023:  ret
    } // end of method MainTest::Func

    注意“try“这一部分的代码——首先ldloc把实体类压入栈中,随后调用get_I(内部生成的函数,用于取出属性I的私有变量数值),随后弹栈把I的内容存入到CS$1$0000中(因为是值类型,因此明显是复制原有的内容)。同时注意在endfinally后ldloc.1弹栈取出CS$1$000的内容(因此仍然为1)。 我们另外可以注意到return的部分是在try……finally……之后才返回的。因此我们可以这样理解Fun静态函数中的内容:

    [C#]

    int C$1$0000 = 0;
    try
    {
       C$1$0000 = f.I;
    }
    finally
    {
       f.Dispose();
    }
    return C$1$0000;

    [VB.NET]

    Dim C$1$0000 As Integer = 0
    Try
      C$1$0000 = f.I
    Finally
      f.Dispose()
    End Try
    Return C$1$0000

    我们发现“C$1$0000”是自生成的(因为需要把p.I压入堆栈的需要)。因此实际返回的是这个临时生成的变量值并非原来的p.I(一般地函数需要返回某个值,都是需要临时在栈中生成一个空间存放这个变量值,然后在弹出返回)。

    以此类推,如果try中返回的是一个引用类型(且这个引用类型在finally中受Dispose影响发生了改变),则即便临时栈中生成了一个引用副本(本质还是引用原来的实体!),并且返回这个副本,由于引用的缘故自然还是以最终的finally后受影响的为准。如下例子(读者自定比较):

    [C#]

    class Fun:IDisposable
    {
       public int I{get;set;}
       public Fun()
        {
             I=1;
        }
       public void Dispose()
       {
              I=0;
       }    
    }
    
    class MainTest
    {
        static Fun Func()
        {
              using(Fun f = new Fun())
             {
                     return f;
             }
        }
        static void Main()
        {
             Console.WriteLine(Func().I);
        }
    }

    [VB.NET]

    Class Fun
        Implements IDisposable
        Public Property I() As Integer
            Get
                Return m_I
            End Get
            Set
                m_I = Value
            End Set
        End Property
        Private m_I As Integer
        Public Sub New()
            I = 1
        End Sub
        Public Sub Dispose()
            I = 0
        End Sub
    End Class
    
    Class MainTest
        Private Shared Function Func() As Fun
            Using f As New Fun()
                Return f
            End Using
        End Function
        Private Shared Sub Main()
            Console.WriteLine(Func().I)
        End Sub
    End Class

    转化对应的IL代码:

     // 代码大小       31 (0x1f)
      .maxstack  2
      .locals init ([0] class CSharp.Fun f,
               [1] class CSharp.Fun CS$1$0000,
               [2] bool CS$4$0001)
      IL_0000:  nop
      IL_0001:  newobj     instance void CSharp.Fun::.ctor()
      IL_0006:  stloc.0
      .try
      {
        IL_0007:  nop
        IL_0008:  ldloc.0
        IL_0009:  stloc.1
        IL_000a:  leave.s    IL_001c
      }  // end .try
      finally
      {
        IL_000c:  ldloc.0
        IL_000d:  ldnull
        IL_000e:  ceq
        IL_0010:  stloc.2
        IL_0011:  ldloc.2
        IL_0012:  brtrue.s   IL_001b
        IL_0014:  ldloc.0
        IL_0015:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
        IL_001a:  nop
        IL_001b:  endfinally
      }  // end handler
      IL_001c:  nop
      IL_001d:  ldloc.1
      IL_001e:  ret
    } // end of method MainTest::Func

    几乎与第一个例子差不多,只不过CS$1$0000是一个引用而非值类型而已!

  • 相关阅读:
    LeetCode OJ String to Integer (atoi) 字符串转数字
    HDU 1005 Number Sequence(AC代码)
    HDU 1004 Let the Balloon Rise(AC代码)
    HDU 1003 Max Sum(AC代码)
    012 Integer to Roman 整数转换成罗马数字
    011 Container With Most Water 盛最多水的容器
    010 Regular Expression Matching 正则表达式匹配
    007 Reverse Integer 旋转整数
    006 ZigZag Conversion
    005 Longest Palindromic Substring 最长回文子串
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/2623247.html
Copyright © 2011-2022 走看看