• 从IL认识关键字(三)


    关键字

         上一篇研究了yield关键字,在本篇研究using关键字。using关键字采用是try-finally结构,本篇主要探讨using结构。

    MSDN解释

      using 关键字有两个用途:

    1. 作为指令,用于为命名空间创建别名或导入其他命名空间中定义的类型。如:
      using System.Text;
    2. 作为语句,用于定义一个范围,在此范围的末尾将释放对象。如:
      using (Font font1 = new Font("Arial", 10.0f))
      {}

      这里我们讨论是第二种情况,作为语句的时候。当作为语句是MSDN上的解释是

      定义一个范围,将在此范围之外释放一个或多个对象。

      

    C# IL Code

       下面以Font画笔作为例子,反编译IL代码研究。

    public void UsingFont()
    {
        using (Font font1 = new Font("Arial", 10.0f))
        {
            bool blod = font1.Bold;
        }
    }

       反编译其IL代码如下:

    .method public hidebysig instance void UsingFont() cil managed
    {
        .maxstack 3
        .locals init (
            [0] class [System.Drawing]System.Drawing.Font font,
            [1] bool flag,
            [2] bool flag2)
        L_0000: nop 
        L_0001: ldstr "Arial"
        L_0006: ldc.r4 10
        L_000b: newobj instance void [System.Drawing]System.Drawing.Font::.ctor(string, float32)
        L_0010: stloc.0 
        L_0011: nop 
        L_0012: ldloc.0 
        L_0013: callvirt instance bool [System.Drawing]System.Drawing.Font::get_Bold()
        L_0018: stloc.1 
        L_0019: nop 
        L_001a: leave.s L_002c
        L_001c: ldloc.0 
        L_001d: ldnull 
        L_001e: ceq 
        L_0020: stloc.2 
        L_0021: ldloc.2 
        L_0022: brtrue.s L_002b
        L_0024: ldloc.0 
        L_0025: callvirt instance void [mscorlib]System.IDisposable::Dispose()
        L_002a: nop 
        L_002b: endfinally 
        L_002c: nop 
        L_002d: ret 
        .try L_0011 to L_001c finally handler L_001c to L_002c
    }

       从最后一行可以看出是一个try-finally结构,在try之前new对象。上面加亮地方解开我一直以来的困扰(一直以为若using里的对象为空,在finally里调用会在finally里引起异常。所以一直自己手动写try-finally语句代替using,从今天开始可以放心使用using语句),加亮的指令

    1. 将索引为0的变量(即font)加载到堆栈
    2. null加载到堆栈
    3. 比较两个值。如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上。
    4. 取出堆栈顶部值并赋值给索引为2的变量(即flag2)
    5. 将索引为2(即flag2)加载到堆栈
    6. 取出堆栈顶部值(即flag2),若为true跳转到L_002b

      由上面上面分析可以写出下面代码:

    public void UsingCode()
    {
        Font font = new Font("Arial", 10.0f);
        try
        {
            bool blod = font.Bold;
        }
        finally
        {
            if (font != null)
            {
                font.Dispose();
            }
        }
    }

     相对于使用using语句,try-finally确实复杂不少,这里不得不佩服微软的语法糖,减少了开发人员的考虑的细节,使代码更加简洁。

    验证代码

       我们写一个自己画笔,实现IDisposable接口。创建对象方法,创建null和对象。

    public class MyFont : IDisposable
    {
        #region IDisposable 成员
        public void Dispose()
        {
            Console.WriteLine("Dispose");
        }
        #endregion
    public static MyFont CreateObject(bool isNull) { if (isNull) { Console.WriteLine("is Null"); return null; } Console.WriteLine("is Object"); return new MyFont(); } }

      调用方法

    static void Main(string[] args)
    {
        using (MyFont mf = MyFont.CreateObject(false))
        {
        }
    
        using (MyFont mf = MyFont.CreateObject(true))
        {
        }
        Console.WriteLine("Finish");
    
        Console.Read();
    }

       运行效果如下:

      和我们猜想一致,当创建对象时,调用Dispose方法,当对象为空时,不会调用Dispose方法。

    下一篇关键字

       以上只是本人的理解与实践,如有错误不足之处希望理解包容,下一篇讨论lock关键字

  • 相关阅读:
    alg--动态规划(dynamic planning)
    alg--分治法
    汇编-理解call,ret
    汇编--实验7
    leetCode笔记--binary tree
    leetCode笔记--(1)
    C#获取当前路径的方法如下
    VS2013 快捷键 与 RESHARPER 冲突
    使用Visual Studio 2013进行单元测试--初级篇
    VS 插件
  • 原文地址:https://www.cnblogs.com/WilsonPan/p/2909488.html
Copyright © 2020-2023  润新知