這個做法在對做法 49 的 Exception Filters 進行補充以及它的特性。

下面這段程式碼 ConsoleLogException 會將 Exception 相關的訊息輸出到 Console 上面,並且注意到最後一行只會回傳 false, 所以使用上就可以透過 when 子句會先對條件進行檢查的特性,來做到安插監控程式碼的功能。

也就是說 ConsoleLogException(e) 這段程式碼在錯誤攔截的時候一定會優先運行,但結果又只會回傳 false 所以不會對結果有任何影響, 所以就很適合拿來寫一些日誌相關的程式碼。

void Main()
{
	try
	{
		data = MakeWebRequest();
	}
	catch (Exception e) when (ConsoleLogException(e)) { }
	catch (TimeoutException e) when (failures++ < 10)
	{
		Console.WriteLine("Timeout error: trying again");
	}
}

public static bool ConsoleLogException(Exception e)
{
	var oldColor = Console.ForegroundColor;
	Console.ForegroundColor = ConsoleColor.Red;
	Console.WriteLine("Error: {0}", e);
	Console.ForegroundColor = oldColor;
	return false;
}

需要注意這種寫法一定要確保回傳的值為 false 絕對不可以是 true 否則錯誤檢查就會停止了,所以我們可以把 catch (Exception e) when (ConsoleLogException(e)) 這段程式碼放在第一個優先檢查的 catch, 就能在任何想要進行輸出檢查的地方進行檢查,同時又不會造成任何影響。

還有另一種放在最後檢查的寫法,這種寫法可以用來記錄 TimeoutException 已經失敗 10 次的錯誤。

void Main()
{
	try
	{
		data = MakeWebRequest();
	}
	catch (TimeoutException e) when (failures++ < 10)
	{
		Console.WriteLine("Timeout error: trying again");
	}
	catch (Exception e) when (ConsoleLogException(e)) { }
}

最後一個寫法可以確保在 Debugger 在連接的狀態底下不會攔截錯誤,下面這段程式碼只要連接上 Debugger 那麼就可知道目前是 測試中那竟沒有必要攔截 TimeoutException,只需要運作第一行的 ConsoleLogException 方法即可。

void Main()
{
	try
	{
		data = MakeWebRequest();
	}
	catch (Exception e) when (ConsoleLogException(e)) { }
	catch (TimeoutException e) when ((failures++ < 10) && (!System.Diagnostics.Debugger.IsAttached))
	{
		WriteLine("Timeout error: trying again");
	}
}

Summary

這個做法透過 Exception Filters 會優先執行 when 字句裡的程式碼的這種特性來達到安插紀錄日誌的程式碼, 在龐大的項目中這個技巧可以幫助開發者更快的發現故障點。