關鍵字
上一篇研究了yield關鍵字,在本篇研究using關鍵字。using關鍵字采用是try-finally結構,本篇主要探討using結構。
MSDN解釋
using 關鍵字有兩個用途:
- 作為指令,用於為命名空間創建別名或導入其他命名空間中定義的類型。如:
using System.Text;
- 作為語句,用於定義一個范圍,在此范圍的末尾將釋放對象。如:
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語句),加亮的指令
- 將索引為0的變量(即font)加載到堆棧
- 將null加載到堆棧
- 比較兩個值。如果這兩個值相等,則將整數值 1 (int32) 推送到計算堆棧上;否則,將 0 (int32) 推送到計算堆棧上。
- 取出堆棧頂部值並賦值給索引為2的變量(即flag2)
- 將索引為2(即flag2)加載到堆棧
- 取出堆棧頂部值(即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關鍵字