Chapter 5 - Item 47 : Create Complete Application-Specific Exception Classes

Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得

例外處理是一種增加程式可靠度的做法,但通常我們在抓取例外時,常常只用到 Exception 父類別。這樣的通用資訊對程式除錯沒有太大幫助(範圍太大且不知道是哪一種例外);作者建議針對可能出現的例外,自定義對應的例外類別;能讓錯誤訊息與程式更完整。

擁有自定義例外處理的程式使用方式:

try
{
	Foo();
	Bar();
}
catch (MyFirstApplicationException e1)
{
	FixProblem(e1);
}
catch (AnotherApplicationException e2)
{
	ReportErrorAndContinue(e2);
}
catch (YetAnotherApplicationException e3)
{
	ReportErrorAndShutdown(e3);
}
catch (Exception e)
{
	ReportGenericError(e);
	throw;
}
finally
{
	CleanupResource();
}

不同的例外有不同的處置方式,程式開發者可以利用 API 提供的例外類別做出相應處置。如果沒有定義不同的例外類別,開發者就只能利用 Exception 父類別中的訊息去推敲,造成流程控制困難。

不好的寫法:

void SampleTwo()
{
	try
	{
		Foo();
		Bar();
	}
	catch (Exception e)
	{
		switch (e.TargetSite.Name)
		{
			case "Foo":
				FixProblem(e);
				break;
			case "Bar":
				ReportErrorAndContinue(e);
				break;
			default:
				ReportErrorAndShutdown(e);
				throw;
		}
	}
	finally
	{
		CleanupResource();
	}
}

看起來很乾淨,統一抓取 Exception 父類別後判斷。但這是不好的做法,僅僅依靠 hard code 方法名稱判斷;若日後方法名修改,則此判斷就失效。

作者建議在自創例外類別時,保留建構子實作。

[Serializable]
public class MyFirstApplicationException : Exception
{
	public MyFirstApplicationException()
		: base()
	{
	}

	public MyFirstApplicationException(string s)
		: base(s)
	{
	}

	public MyFirstApplicationException(string s, Exception e)
		: base(s, e)
	{
	}

	// .NET Core 有可能不支援。
	protected MyFirstApplicationException(SerializationInfo info, StreamingContext cxt)
		: base(info, cxt)
	{
	}
}

最後,如果程式有利用到第三方元件;且有可能擲出例外時,也是用自定義例外將底層例外包裝,讓擲出的例外可讀性更好。

public double DoSomeWork()
{
	// 第三方元件可能拋出例外。
	return ThirdPartyLibrary.ImportantRoutine();
}

public double DoSomeWork2()
{
	try
	{
		// 第三方元件可能拋出例外。
		return ThirdPartyLibrary.ImportantRoutine();
	}
	catch (ThirdPartyException e)
	{		
		var msg = $"Problem with {ToString()} using library";
		throw new DoingSomeWorkException(msg, e);
	}

}
結論:
1. 利用自定義例外類別,讓呼叫端有機會做相應處理。
2. 利用自定義例外類別封裝底層拋出的例外,提高呼叫端收到的例外訊息可讀性。