從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關鍵字


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM