程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 淺談Try catch finally與using

淺談Try catch finally與using

編輯:關於.NET

對於Try catch finally,大家應該都不陌生,您接觸的寫法可能會是下面的記幾種類型:

Try catch (您可以匹配多個catch)

try
{
}
catch (Exception)
{
throw;
}

Try finally 
try
{
}
finally
{
}

Try catch finally (同樣,你一樣可以匹配多個catch)

Try catch finally
try
{
}
catch (ArgumentNullException e)
{ }
catch (Exception ex)
{ }
finally
{
}

在這裡,finally的作用簡單的一句話說就是“無論try裡面的代碼正常執行或者發生異常,都會繼續執行finally裡面的代碼”,所以我們一般會在finally裡面執行我們的一些清理操作。尤其對於操作一些非托管資源或者比較珍貴的資源的時候,執行必要的清理操作顯得尤為重要,具體的解釋您可以參考MSDN。

說了這些,我們來看看try finally,不知道您平時是使用try finally,還是會使用更簡潔的語法using {}。對於using, 我這裡並不是想詳細的解釋它的用法,如果您想了解,您請看這裡。我們都知道using只是為了讓語法變的更簡潔而已,我不知道在這裡用語法糖這個詞來形容它是否合適。為了驗證try finally和using是否一致,我再次查看了編譯之後的代碼(這裡我還是使用MSDN的例子):

代碼

{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}

我們看一下編譯之後的結果(我只是截取了有用的部分代碼):

using
.try
{
IL_0012:  nop
IL_0013:  ldloc.0
IL_0014:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
IL_0019:  stloc.1
IL_001a:  nop
IL_001b:  leave.s    IL_002f
}  // end .try
finally
{
IL_001d:  nop
IL_001e:  ldloc.0
IL_001f:  ldnull
IL_0020:  ceq
IL_0022:  stloc.3
IL_0023:  ldloc.3
IL_0024:  brtrue.s   IL_002d
IL_0026:  ldloc.0
IL_0027:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
IL_002c:  nop
IL_002d:  nop
IL_002e:  endfinally
}  // end handler

using
.try
{
IL_0041:  nop
IL_0042:  ldloc.0
IL_0043:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
IL_0048:  stloc.1
IL_0049:  nop
IL_004a:  leave.s    IL_005c
}  // end .try
finally
{
IL_004c:  ldloc.0
IL_004d:  ldnull
IL_004e:  ceq
IL_0050:  stloc.2
IL_0051:  ldloc.2
IL_0052:  brtrue.s   IL_005b
IL_0054:  ldloc.0
IL_0055:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
IL_005a:  nop
IL_005b:  endfinally
}  // end handler

沒什麼區別,不是嗎?到這裡我產生兩個疑問,1. 那麼對於try catch和try catch finally編譯之後會是什麼樣子呢? 2. 如果using裡面的代碼產生異常怎麼辦呢?於是我編譯了try catch finally代碼:

Try catch finally
.try
{
.try
{
IL_006e:  nop
IL_006f:  ldloc.0
IL_0070:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
IL_0075:  stloc.1
IL_0076:  nop
IL_0077:  leave.s    IL_007e
}  // end .try
catch [mscorlib]System.Object 
{
IL_0079:  pop
IL_007a:  nop
IL_007b:  nop
IL_007c:  leave.s    IL_007e
}  // end handler
IL_007e:  nop
IL_007f:  leave.s    IL_0093
}  // end .try
finally
{
IL_0081:  nop
IL_0082:  ldloc.0
IL_0083:  ldnull
IL_0084:  ceq
IL_0086:  stloc.2
IL_0087:  ldloc.2
IL_0088:  brtrue.s   IL_0091
IL_008a:  ldloc.0
IL_008b:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
IL_0090:  nop
IL_0091:  nop
IL_0092:  endfinally
}  // end handler

你仔細看上面的代碼,編譯器把try catch finally塊分解了,新增加了一個try,把try catch塊放在 裡面,外面套嵌了finally,看來雖然我們自己把try catch finally三者寫在一起,當成一個"塊",但是編譯器會分開處理。

那麼對於using產生異常的時候會怎麼樣呢?我們看下面的代碼:

隨便定義一個類

public class Test : IDisposable
{
public int ID;
#region IDisposable Members
public void Dispose()
{
Console.WriteLine(".......................");
}
#endregion
}

using (var test = new Test())
{
test.ID = Int32.Parse("a");
}

上面的代碼執行肯定會拋出異常,但是您如果強制繼續執行的話,你會看到"............................" 的輸出。我們的目的達到了,雖然程序產生了異常,但是我們的清理資源的代碼還是執行了。但是這會出來一個很不友好的界面,告訴你程序掛掉了。我想任何一個用戶都不希望看到這個。那我們怎麼辦呢?是繼續用代碼貌似不夠簡潔的Try catch finally還是在using裡面加上catch來捕獲異常呢?寫成這種形式嗎?

加強版的using

using (var test = new Test())
{
try
{
test.ID = Int32.Parse("a");
}
catch (Exception) { }
}

這樣的語法編譯出來和Try catch finally是一樣的效果,但是代碼要簡潔一些。但是每次用using我都需要自己手動加上上面的代碼,讓我覺得很不好。還好vs裡面using是通過 Code Snippets來實現的,所以我考慮可以在這裡面動一動手腳了。於是我添加了一個新的Snippets文件,將using裡面的內容拷過來,修改如下:

usingTry
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>usingTry</Title>
<Shortcut>usingTry</Shortcut>
<Description>Code snippet for using statement add Try</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>resource</ID>
<ToolTip>Resource to use</ToolTip>
<Default>resource</Default>
</Literal>
<Literal>
<ID>expression</ID>
<ToolTip>Exception type</ToolTip>
<Function>SimpleTypeName(global::System.Exception)</Function>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[
using($resource$)
{
try 
{            
$selected$
}
catch ($expression$)
{
$end$
}
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>

至此,完成了一個加強版的using,和使用普通的using是一樣的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved