Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得
try catch 區塊中的 catch,時常會呼叫 throw 重新擲出例外以處理無法回復的例外。重新擲出例外不僅增加運行階段支出成本,更重要是,重新擲出例外會讓喪失呼叫端的資訊。本節提出利用 when 條件式來處理例外,延遲例外的判斷時機;同時也保留呼叫端的資訊。
範例:
var retryCount = 0;
var dataString = default(string);
while (dataString == null)
{
try
{
dataString = MakeWebRequest();
}
catch (TimeoutException ex) when (retryCount++ < 3)
{
Debug.WriteLine("Operation timed out. Trying again.");
// 延遲一段時間並重試。
Thread.Sleep(retryCount * 1000);
}
}
這段程式碼會嘗試抓取 TimeoutException,當重試次數小於三次時自動延遲一段時間並重試。當不符合上述情況時,將繼續往上層找,直到找到能處理例外的程式碼為止;所有的運行階段資訊都被保留起來。
下面是重新擲出例外的寫法:
var retryCount = 0;
var dataString = default(string);
while (dataString == null)
{
try
{
dataString = MakeWebRequest();
}
catch (TimeoutException ex)
{
if( retryCount++< 3 )
{
Debug.WriteLine("Timed out. Trying again.");
// 延遲一段時間並重試。
Thread.Sleep(retryCount * 1000);
}
else
throw;
}
}
同樣的嘗試捕捉 TimeoutException,但擲出的例外 call stack 會從 throw 開始記錄(也就是 catch block);呼叫端的資訊已經遺失。
下面用簡單的例子說明擲出例外的資訊不同之處:
void TreeOfError()
{
try
{
SingleBadThing();
}
catch (Exception ex)
{
// Reported on Call Stack.
throw;
}
}
void TreeOfError2()
{
try
{
SingleBadThing(); // Reported on Call Stack.
}
catch (Exception ex) when (false)
{
Debug.WriteLine("Can't happen");
}
}
void SingleBadThing()
{
throw new NotImplementedException();
}
TreeOfError 在 Debug 時的 CallStack 最上層只記錄到 TreeOfError 方法,但實際上擲出例外的是 SingleBadThing 方法。try 區塊可能呼叫了不同方法,這時要再去追蹤擲出例外的方法為何就很困難;而 TreeOfError2 則保留了擲出例外方法的資訊,我們可以很輕易的確定出問題的方法是誰。
結論:
1. 利用 when 條件式保留 CallStack 資訊。
2. 避免重新擲出例外,以減少運行階段資源支出。
1. 利用 when 條件式保留 CallStack 資訊。
2. 避免重新擲出例外,以減少運行階段資源支出。