本文鏈接: https://www.cnblogs.com/hubaijia/p/about-exceptions-2.html
系列文章:
- 關于Exception的幾點思考和在專案中的使用(一)
- 關于Exception的幾點思考和在專案中的使用(二)
本文目錄
目錄- 與Exception相關的檔案結構
- ExceptionFactory 和 Ensure
- Exception的可見性
- 結語
與Exception相關的檔案結構
在上一篇我們提到了 集中化管理 Exceptions,這樣所有的Exception的產生都在同一檔案中,便于我們后期的Review、重構,不會看到漫天飛舞的throw new Exceptions(...),也盡量避免了同一種類的Exception擁有著不同的Message,記錄著不同的引數資訊,
此外在上一篇中我們還提出了細化Exception的方式,即按照 型別、ErrorCode、Cause 以此細化,
舉例來說,專案中會形成如下的檔案結構:(實體代碼請訪問 Github)

綠框里的就是Exception相關的代碼檔案,其中XXX_ErrorCodes, XXX_ExceptionFactory等型別應該標記為internal,即只是類別庫內部可見,
在上述檔案結構中,我簡要的模擬了一個專案的分層結構,不一定都是這樣,但大致如下:
- Common 是專案公共類別庫,放著各種輔助代碼、框架代碼等等,代表著你專案的基礎部分;
- Dal 放著連接各種Store(MySql、Redis等等)的代碼,即放DataAccessObject的;
- Repo 屏蔽各種細節,直接為各種Service提供服務;
- Services 表示你的各項業務模塊,當然你的專案結構中有不同的叫法和含義,大家各自知道就行;
- Application 具體的應用,提供Endpoint,開放Service的各項功能,面向呼叫者,
為什么要詳細描述一個專案分層結構,因為一會兒我們需要解決一個問題,就是Exception的可見性,
先賣個關子,一會兒再說,在此之前,先解決一個小問題,
ExceptionFactory 和 Ensure
將Exception集中化管理,除了我們用的ExceptionFactory,還有一種寫法我們經常見到,那就是Ensure,或者EnsureXXX,
參閱.net core的源代碼,我們會看到非常多的Ensure類,源代碼連接 https://source.dot.net/#q=Ensure,
我們經常把 復雜 或者 重復 出現的判斷寫到Ensure中,Ensure的中文意思“確保”正是這個含義,
示例代碼如下:
// Ensure 寫法
internal static class Ensure
{
public static void NickNameNotExisted(string newNickName)
{
bool alreadyExisted = true;
// Some Check
if(alreadyExisted)
{
throw IdentityExceptionFactory.NickNameExisted();
}
}
public static T NotNull<T>([NotNull]T? obj, string paramName) where T : class
{
if (obj == null)
{
throw new ArgumentNullException(paramName);
}
return obj;
}
}
我們觀察到,Ensure類中的Exception也是由ExceptionFactory生成的(當然那些基礎Exception型別,比如ArgumentNullException就直接new 了),
即Ensure類是對判斷(if陳述句等)的抽象,而ExceptionFactory只是Exception的生成器,
當然,當我們不直接在現場拋出例外,而是呼叫Ensure類方法拋出例外,會稍微有一些不同:
- Stack Trace不同,第一行永遠是Ensure的方法
- 沒有什么大不了,因為Stack Trace會詳細記錄后續的呼叫;
- 代碼邏輯上不如直接寫 throw 那么直白
- 明確使用Ensure這一稱呼,寫到代碼規則里,團隊內統一,一看到Ensure就知道可能要拋出例外,
- 注意CodeAnalysis 和 NRT(null reference types)
- 如果專案開啟上面兩項功能,需要添加相應的Attribute,比如,上面代碼的
NotNull方法,否則在Ensure后,CodeAnalysis還會提醒你CS8602等錯誤.
- 如果專案開啟上面兩項功能,需要添加相應的Attribute,比如,上面代碼的
Exception的可見性
舉例來說,就是 DalException 要不要對Service可見,還是只對Repo可見?
其實可見或者不可見都沒有明顯的錯誤,但總的來說,
- 隱藏并包裝下層的Exception,對呼叫者更友好些,
- 比如在WebApplication專案中,我們就可以只面對來自Service的Exception,不用去知道Dal或者Repo的細節,
- 而來自IdentityService的例外,只有IdentityException一種(不算ArgumentNull那些基本Exception)
- 隱藏并包裝下層的Exception,可以在每一層加入更多有用的資訊
- 如果是呼叫第三方類別庫,盡量隱藏和包裝成自己的例外型別,比如你在Dal中呼叫MySqlConnector類別庫,那么將
MySqlException放到DalException的innerException中去,讓程式的其他部分不需要面對一個可能更換掉的外來者,
結語
以上寫的都比較具體,所以如果與大家的實際使用不同,請多多交流,共同進步,我也會補充到文章里來,
下一篇,我會講講關于 捕捉Exception的幾點實際經驗,比如全域例外處理以及異步編程中的例外,
謝謝閱讀,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/274649.html
標籤:.NET技术
下一篇:請教一個排列演算法
