[.NET] using區段是否等於try/finally

我們都知道using可以釋放實作IDisposable介面的類別,主要是釋放非托管的物件,在操作檔案的時候就必須要釋放才不會造成檔案鎖定,[.NET] 使用 using 或 try/finally 清理資源,使用

try/finally的寫法如下

public string ReaderLine(string FileName)

{

    if (!File.Exists(FileName))

        return null;

    Stream stream = null;

    StreamReader reader = null;

    string line = "";

    StringBuilder sb = new StringBuilder();

    try

    {

        stream = File.Open(FileName, FileMode.Open);

        reader = new StreamReader(stream);

        while ((line = reader.ReadLine()) != null)

        {

            sb.AppendLine(line);

        }



        return sb.ToString();

    }

    finally

    {

        if (stream != null)

            stream.Close();

        if (reader != null)

            reader.Close();

    }

}

 

使用using的寫法如下

public string ReaderLine(string FileName)

{

    if (!File.Exists(FileName))

        return null;



    string line = "";

    StringBuilder sb = new StringBuilder();

    using (Stream stream = File.Open(FileName, FileMode.Open))

    {

        using (StreamReader reader = new StreamReader(stream))

        {

            while ((line = reader.ReadLine()) != null)

            {

                sb.AppendLine(line);

            }

            return sb.ToString();

        }

    }

}


上述的寫法例外發生時會被吃掉嗎?

我相信很多人對上述的寫法會有疑問,我們來做個小實驗,我在try區塊以及using區塊裡面故意寫轉型失敗的程式碼,我們可以發現VS仍有拋出例外訊息。

image

image

所以不管是using還是try/finally都不會吃掉例外訊息。


using和try/finally有什麼不同?

基本上它們兩個是一樣的東西,先來用Reflector看看using所產生的IL,using區段變成try/finlly了

image

.method public hidebysig instance string ReaderLine(string FileName) cil managed

{

    .maxstack 2

    .locals init (

        [0] string line,

        [1] class [mscorlib]System.Text.StringBuilder sb,

        [2] class [mscorlib]System.IO.Stream stream,

        [3] class [mscorlib]System.IO.StreamReader reader,

        [4] string a,

        [5] uint8 b,

        [6] string CS$1$0000,

        [7] bool CS$4$0001)

    L_0000: nop 

    L_0001: ldarg.1 

    L_0002: call bool [mscorlib]System.IO.File::Exists(string)

    L_0007: stloc.s CS$4$0001

    L_0009: ldloc.s CS$4$0001

    L_000b: brtrue.s L_0012

    L_000d: ldnull 

    L_000e: stloc.s CS$1$0000

    L_0010: br.s L_008d

    L_0012: ldstr ""

    L_0017: stloc.0 

    L_0018: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()

    L_001d: stloc.1 

    L_001e: ldarg.1 

    L_001f: ldc.i4.3 

    L_0020: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Open(string, valuetype [mscorlib]System.IO.FileMode)

    L_0025: stloc.2 

    L_0026: nop 

    L_0027: ldloc.2 

    L_0028: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(class [mscorlib]System.IO.Stream)

    L_002d: stloc.3 

    L_002e: nop 

    L_002f: br.s L_003b

    L_0031: nop 

    L_0032: ldloc.1 

    L_0033: ldloc.0 

    L_0034: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)

    L_0039: pop 

    L_003a: nop 

    L_003b: ldloc.3 

    L_003c: callvirt instance string [mscorlib]System.IO.TextReader::ReadLine()

    L_0041: dup 

    L_0042: stloc.0 

    L_0043: ldnull 

    L_0044: ceq 

    L_0046: ldc.i4.0 

    L_0047: ceq 

    L_0049: stloc.s CS$4$0001

    L_004b: ldloc.s CS$4$0001

    L_004d: brtrue.s L_0031

    L_004f: ldstr "999"

    L_0054: stloc.s a

    L_0056: ldloc.s a

    L_0058: call uint8 [mscorlib]System.Byte::Parse(string)

    L_005d: stloc.s b

    L_005f: ldloc.1 

    L_0060: callvirt instance string [mscorlib]System.Object::ToString()

    L_0065: stloc.s CS$1$0000

    L_0067: leave.s L_008d

    L_0069: ldloc.3 

    L_006a: ldnull 

    L_006b: ceq 

    L_006d: stloc.s CS$4$0001

    L_006f: ldloc.s CS$4$0001

    L_0071: brtrue.s L_007a

    L_0073: ldloc.3 

    L_0074: callvirt instance void [mscorlib]System.IDisposable::Dispose()

    L_0079: nop 

    L_007a: endfinally 

    L_007b: ldloc.2 

    L_007c: ldnull 

    L_007d: ceq 

    L_007f: stloc.s CS$4$0001

    L_0081: ldloc.s CS$4$0001

    L_0083: brtrue.s L_008c

    L_0085: ldloc.2 

    L_0086: callvirt instance void [mscorlib]System.IDisposable::Dispose()

    L_008b: nop 

    L_008c: endfinally 

    L_008d: nop 

    L_008e: ldloc.s CS$1$0000

    L_0090: ret 

    .try L_002e to L_0069 finally handler L_0069 to L_007b

    .try L_0026 to L_007b finally handler L_007b to L_008d

}

 

再看看Reflector不優化IL的結果,選C# None,Reflector會幫我們直接翻譯IL成C#,當然你還可以翻成其它.NET語言

image

public string ReaderLine(string FileName)

{

    string line;

    StringBuilder sb;

    Stream stream;

    StreamReader reader;

    string a;

    byte b;

    string CS$1$0000;

    bool CS$4$0001;

    if (File.Exists(FileName) != null)

    {

        goto Label_0012;

    }

    CS$1$0000 = null;

    goto Label_008D;

Label_0012:

    line = "";

    sb = new StringBuilder();

    stream = File.Open(FileName, 3);

Label_0026:

    try

    {

        reader = new StreamReader(stream);

    Label_002E:

        try

        {

            goto Label_003B;

        Label_0031:

            sb.AppendLine(line);

        Label_003B:

            if ((((line = reader.ReadLine()) == null) == 0) != null)

            {

                goto Label_0031;

            }

            a = "999";

            b = byte.Parse(a);

            CS$1$0000 = sb.ToString();

            goto Label_008D;

        }

        finally

        {

        Label_0069:

            if ((reader == null) != null)

            {

                goto Label_007A;

            }

            reader.Dispose();

        Label_007A:;

        }

    }

    finally

    {

    Label_007B:

        if ((stream == null) != null)

        {

            goto Label_008C;

        }

        stream.Dispose();

    Label_008C:;

    }

Label_008D:

    return CS$1$0000;

}


後記:

由上面的演示我們可以知道

1.using跟try/finally,都不會吃掉例外訊息,因為沒有寫catch區段。

2.using是try/finally的簡易寫法。

兩者的寫法結果都一樣,就看自己喜歡什麼樣子的寫法,using的寫法看起來比較短,若只有一層我會使用,但如果有多層using(兩層以上),我就會覺得閱讀上有很大的不便,我就不會採用這樣的寫法。

你可能感兴趣的:(finally)