程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Effective C#原則45:選擇強異常來保護程序(1)

Effective C#原則45:選擇強異常來保護程序(1)

編輯:關於C語言
你拋出異常時,你就在應用程序中引入了一個中斷事件。而且危機到程序 的控制流程。使得期望的行為不能發生。更糟糕的是,你還要把清理工作留給最 終寫代碼捕獲了異常的程序員。而當一個異常發生時,如果你可以從你所管理的 程序狀態中直接捕獲,那麼你還可以采取一些有效的方法。謝天謝地,C#社區不 須要創建自己的異常安全策略,C++社區裡的人已經為我們完成了所有的艱巨的 工作。以Tom Cargill的文章開頭:“異常處理:一種錯誤的安全感覺, ” 而且Herb Sutter,Scott Meyers,Matt Austern,Greg Colvin和Dave Abrahams也在後繼寫到這些。C++社區裡的大量已經成熟的實踐可以應用在C#應 用程序中。關於異常處理的討論,一直持續了6年,從1994年到2000年。他們討論,爭論,以及驗證很多解決困難問題的方法。我們應該在C#裡利用所有這些艱 難的工作。

Dave Abrahams定義了三種安全異常來保證程序:基本保護, 強保證,以及無拋出保證。Herb Sutter在他的Exceptional C++(Addison- Wesley, 2000)一書討論了這些保證。基本保證狀態是指沒有資源洩漏,而且所 有的對象在你的應用程序拋出異常後是可用的。強異常保證是創建在基本保證之 上的,而且添加了一個條件,就是在異常拋出後,程序的狀態不發生改變。無拋 出保證狀態是操作決對不發生失敗,也就是從在某個操作後決不會發生異常。強 異常保證在從異常中恢復和最簡單異常之間最平衡的一個。基本保證一般在 是.Net和C#裡以默認形式發生。運行環境處理托管內存。只有在一種情況下,你 可能會有資源洩漏,那就是在異常拋出時,你的程序占有一個實現了 IDisposable接口的資源對象。原則18解釋了如何在對面異常時避免資源洩漏。

強異常保證狀態是指,如果一個操作因為某個異常中斷,程序維持原狀 態不改變。不管操作是否完成,都不修改程序的狀態,這裡沒有折衷。強異常保 證的好處是,你可以在捕獲異常後更簡單的繼續執行程序,當然也是在你遵守了 強異常保證情況下。任何時候你捕獲了一個異常,不管操作意圖是否已經發生, 它都不應該開始了,而且也不應該做任何修改。這個狀態就像是你還沒有開始這 個操作行為一樣。

很多我所推薦的方法,可以更簡單的幫助你來確保進 行強異常保證。你程序使用的數據元素應該存為一個恆定的類型(參見原則6和原 則7)。如果你組並這兩個原則,對程序狀態進行的任何修改都可以在任何可能引 發異常的操作完成後簡單的發生。常規的原則是讓任何數據的修改都遵守下面的 原則:

1、對可能要修改的數據進行被動式的拷貝。

2、在拷貝的 數據上完成修改操作。這包括任何可能異常異常的操作。

3、把臨時的拷 貝數據與源數據進行交換。 這個操作決不能發生任何異常。

做為一個例 子,下面的代碼用被動的拷貝方式更新了一個雇員的標題和工資 :

public void PhysicalMove( string title, decimal newPay )
{
 // Payroll data is a struct:
 // ctor will throw an exception if fIElds aren't valid.
 PayrollData d = new PayrollData( title, newPay,
  this.payrollData.DateOfHire );
 // if d was constructed properly, swap:
 this.payrollData = d;
}

有些時候,這種強保證只是效率很低而不被支持,而 且有些時候,你不能支持不發生潛在BUG的強保證。開始的那個也是最簡單的那 個例子是一個循環構造。當上面的代碼在一個循環裡,而這個循環裡有可能引發 程序異常的修改,這時你就面臨一個困難的選擇:你要麼對循環裡的所有對象進 行拷貝,或者降低異常保證,只對基本保證提供支持。這裡沒有固定的或者更好 的規則,但在托管環境裡拷貝堆上分配的對象,並不是像在本地環境上那開銷昂 貴。在.Net裡,大量的時間都花在了內存優化上。我喜歡選擇支持強異常保證, 即使這意味要拷貝一個大的容器:獲得從錯誤中恢復的能力,比避免拷貝獲得小 的性能要劃算得多。在特殊情況下,不要做無意義的拷貝。如果某個異常在任何 情況下都要終止程序,這就沒有意義做強異常保證了。我們更關心的是交換引用 類型數據會讓程序產生錯誤。考慮這個例子:

private DataSet _data;
public IListSource MyCollection
{
 get
  {
  return _data;
 }
}
public void UpdateData( )
{
 // make the defensive copy:
 DataSet tmp = _data.Clone( ) as DataSet;
 using ( SqlConnection myConnection =
  new SqlConnection( connString ))
 {
   myConnection.Open();
  SqlDataAdapter ad = new SqlDataAdapter( commandString,
   myConnection );
  // Store data in the copy
  ad.Fill( tmp );
  // it worked, make the swap:
  _data = tmp;
 }
}

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