再議.Net中null的使用規范
在上一文中,論述兩個.Net Framework對null應用不夠合理的例子。大家評論中,給出了不少指導性意見,這里也對.Net中null的使用規范作一下總結。
1. Empty代表瓶子是空的,null代表瓶子都沒有
首先要明確你的“瓶子”是什么,也就是你代碼的邏輯是建立在什么基礎或前提之上。如果這個前提不存在,是否為正常的,或是可接受的情況。如果是,則應該允許返回null。
例如ConfigurationElement,既然允許某個節點屬性未定義,自然應該允許null。如果前提因為意外(罕見的情況)未實現,則應該拋出異常,交給上一級堆棧進行處理。相應的,Linq中的FirstOrDefault方法,也是允許“不存在符合條件元素”這個前提被下,返回了null。
2. Null代表未初始化的引用類型成員
引用類型成員并不一定會在定義或構造函數中就初始化。一種情況,是為了性能考慮,進行延時初始化,如單例模式中。但是,null值不應該傳遞給外部。
{
if (instance==null)
{
lock (L)
{
if (instance==null)
{
instance = new Singleton();
}
}
}
return instance;
}
另一種情況,是考慮擴展性,將個別成員留空。如適配器模式中,Asp.Net Page在呈現時,會檢查其Adapter屬性是否為null,如不是null,則調用Adapter負責呈現。
3. 盡可能減少返回null的場景
留意了下.Net Framework的函數,返回null的還真是很少見。一返回null,調用函數就不得不進行判斷,增加了復雜性,及出錯的機率。通過對代碼結構進行適當調整優化,應該可以減少null的判斷。尤其是框架開發,在公開的API函數中,返回Null的情況應該越少越好。例外的可能是一些按索引取值的屬性,如HttpRequest.Form。
如果是要返回一個集合類型,只要執行無異常,寧可為空也不要返回null。
4. 要對外部數據進行null判斷
在你公開的API中,必須考慮被其他程序集調用,接收到null參數的情況,不管是什么原因傳入的。
5. 不要讓null參數表示特殊含義
如果API中,接收null參數表示一個截然不同的場景,傳參模塊與接收模塊間形成了控制耦合。增加了程序理解難度,又容易出錯。推薦的做法是,將不同的場景用不同的模塊或函數進行分別處理。比如XmlSchema.Add方法,提供一個重載,只接收xsd文件路徑,就可以消除這種耦合。
6. 讓程序拋出ArgumentNullException而不是NullReferenceException
空引用異常總是由CLR拋出的,不應該出現在邏輯嚴密的程序中。而應該在函數開始的參數判斷中,就要拋出ArgumentNullException。或者是在函數執行過程中,調用其他函數得到了null,要么對其進行判斷予以區別處理,要么拋出新的異常。
相信如果能遵守這幾個規范,一定會減輕許多null帶給我們的麻煩和困擾。Null,其實挺好。