再议.Net中null的使用规范
在上一文中,论述两个.Net Framework对null应用不够合理的例子。大家评论中,给出了不少指导性意见,这里也对.Net中null的使用规范作一下总结。
1. Empty代表瓶子是空的,null代表瓶子都没有
首先要明确你的“瓶子”是什么,也就是你代码的逻辑是建立在什么基础或前提之上。如果这个前提不存在,是否为正常的,或是可接受的情况。如果是,则应该允许返回null。
例如ConfigurationElement,既然允许某个节点属性未定义,自然应该允许null。如果前提因为意外(罕见的情况)未实现,则应该抛出异常,交给上一级堆栈进行处理。相应的,Linq中的FirstOrDefault方法,也是允许“不存在符合条件元素”这个前提被下,返回了null。
2. Null代表未初始化的引用类型成员
引用类型成员并不一定会在定义或构造函数中就初始化。一种情况,是为了性能考虑,进行延时初始化,如单例模式中。但是,null值不应该传递给外部。
1 2 3 | <div class = "cnblogs_code" onclick= "cnblogs_code_show('fd2eafce-a524-4428-8cea-a179046c131d')" ><img id= "code_img_closed_fd2eafce-a524-4428-8cea-a179046c131d" class = "code_img_closed" style= "display: none;" src= "https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt= "" ><div id= "cnblogs_code_open_fd2eafce-a524-4428-8cea-a179046c131d" ><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style= "color: #0000ff;" > get </span><span style= "color: #000000;" ><br>{<br> </span><span style= "color: #0000ff;" > if </span><span style= "color: #000000;" > (instance</span><span style= "color: #000000;" >==</span><span style= "color: #000000;" > null )<br> {<br> </span><span style= "color: #0000ff;" > lock </span><span style= "color: #000000;" > (L)<br> {<br> </span><span style= "color: #0000ff;" > if </span><span style= "color: #000000;" > (instance</span><span style= "color: #000000;" >==</span><span style= "color: #000000;" > null )<br> {<br> instance </span><span style= "color: #000000;" >=</span><span style= "color: #000000;" > </span><span style= "color: #0000ff;" > new </span><span style= "color: #000000;" > Singleton();<br> }<br> }<br> }<br> </span><span style= "color: #0000ff;" > return </span><span style= "color: #000000;" > instance;<br>}</span></div></pre> </div> </div> |
另一种情况,是考虑扩展性,将个别成员留空。如适配器模式中,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,其实挺好。