C# try catch finally

來源:互聯網
上載者:User

前言

 catch 和 finally 一起使用的常見方式是:在 try 塊中擷取並使用資源,在 catch 塊中處理異常情況,並在 finally 塊中釋放資源。

Catch

  catch 這將捕獲任何發生的異常。

  catch(Exception e) 這將捕獲任何發生的異常。另外,還提供e參數,你可以在處理異常時使用e參數來獲得有關異常的資訊。

  catch(Exception的衍生類別 e) 這將捕獲衍生類別定義的異常,例如,我想捕獲一個無效操作的異常,可以如下寫: catch(InvalidOperationException e) { .... } 這樣,如果try語句塊中拋出的異常是InvalidOperationException,將轉入該處執行,其他異常不處理。

  catch可以有多個,也可以沒有,每個catch可以處理一個特定的異常。.net按照你catch的順序尋找異常處理塊,如果找到,則進行處理,如果找不到,則向上一層次拋出。如果沒有上一層次,則向使用者拋出,此時,如果你在調試,程式將中斷運行,如果是部署的程式,將會中止。

  如果沒有catch塊,異常總是向上層(如果有)拋出,或者中斷程式運行。

Finally

  finally可以沒有,也可以只有一個。無論有沒有發生異常,它總會在這個異常處理結構的最後運行。即使你在try塊內用return返回了,在返回前,finally總是要執行,這以便讓你有機會能夠在異常處理最後做一些清理工作。如關閉資料庫連接等等。 注意:如果沒有catch語句塊,那麼finally塊就是必須的。

  如果你不希望在這裡處理異常,而當異常發生時提交到上層處理,但在這個地方無論發生異常,都要必須要執行一些操作,就可以使用try finally, 很典型的應用就是進行資料庫操作: 用下面這個原語來說明:

        try         {             DataConnection.Open();            DataCommand.ExecuteReader();            ...             return;         }         finally        {            DataConnection.Close();         }

 

無論是否拋出異常,也無論從什麼地方return返回,finally語句塊總是會執行,這樣你有機會調用Close來關閉資料庫連接(即使未開啟或開啟失敗,關閉操作永遠是可以執行的),以便於釋放已經產生的串連,釋放資源。

return

 下面來看第一個小例子

using System;public class Test1{    public static void Main()    {        Console.WriteLine(Test());        Console.ReadLine();    }    public static int   Test()    {        int i=1;        try        {            return i;        }        finally        {            i++;        }    }}

列印出來的結果為1.
第二個例子

using System;public class Class1{    public int Value1=1;}public class Test1{    public static void Main()    {        Console.WriteLine(Test().Value1);        Console.ReadLine();    }    public static Class1  Test()    {        Class1 c=new Class1();        try        {            return c;        }        finally        {            c.Value1++;        }    }}

運行後結果為2.

要解釋這種區別,就需要看看其IL是什麼,從調用函數、參數棧的角度來理解。CLR在執行中也有棧,但這個棧的用途與傳統的本地代碼中的棧並不完全相同。本地代碼中棧的用處非常大,不但可以用來臨時儲存寄存器的值,還用來儲存局部變數,此外還用來儲存部分或全部傳給函數的參數,而函數的傳回值一般是通過EAX寄存器來傳遞的,而不是用棧。但在CLR中,局部變數並非顯式的用棧來儲存,棧只是用來調用函數時傳遞參數,此外,函數的傳回值也是用棧來儲存的。當調用一個函數時,將函數所需要的參數依次壓棧,函數裡面直接取用這些參數,在函數返回時將傳回值壓棧,函數返回後,棧頂即是傳回值。如果調用者並不關心傳回值,那麼需要執行一下pop語句,把傳回值彈出,這樣保證函數在調用前後棧頂的位置是相同的。
當通過壓棧傳遞參數時,參數的類型不同,壓棧的內容也不同。如果是實值型別,壓棧的就是經過複製的參數值,如果是參考型別,那麼進棧的只是一個引用,這也就是我們所熟悉的,傳遞實值型別時,函數內修改參數值不會影響函數外,而參考型別的話則會影響。

代碼中當我們執行new時,對應的IL是newobj,其結果是建立一個TestClass2類型的對像並返回一個引用放置於棧上,之後的stloc就將這個引用儲存為局部變數,於是棧上沒有了其他內容。Try塊並沒有執行太多操作,只是把剛儲存的引用再放到棧上,再儲存為另一個局部變數,這個局部變數就是稍後要返回的引用,此時我們擁有兩個局部變數,但它們是指向同一個對象的兩個引用。Finally塊先拿出開始時儲存的引用放到棧上,dup語句使得棧頂再增加一個完全一樣的引用,之後ldfld語句是從棧頂對象取一個成員放到棧上,所取的成員是value,之後再往棧上壓一個1,再執行add,就實現了1+1=2的過程,add從棧上彈出兩個值,再向棧壓回一個值。此時再調用stfld就把剛剛壓棧的2設定給棧上2之下的那個引用所指對象的value屬性上。而在finally之後的部分才是真正的return,它試圖取出我們所儲存的第二個局部變數壓棧,將它作為傳回值。但對於參考型別來說,它與先前所操作的引用所指的是同一對象,因此finally塊中的操作會影響到傳回值,也就非常好理解了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.