.Net令人纠结的Null

  从我们刚学.Net编程起,我们的程序不断被从天而降NullReferenceException打断。直到今天,我们仍然时常为C#的Null或者VB的Nothing困惑。什么情况下我们该返回null,如果参数是null代表什么。许多类型,有两种不同意义的空状态,一种是null,一种是其本身或其某个属性集合中没有元素,这就更容易产生误用。常听有人说,Null这个概念在编程语言中根本不应该存在。但是,从C++到Java到.Net,它从未离开过。

  最近,注意到.Net Framework在读取程序配置文件的一个小Bug。比如我在配置文件中,自定义了名为ReviewPeriod的节点:

<configuration>

<configSections>

<section name="reviewPeriod" type="WordPadTest.ReviewPeriod,WordPadTest"/>

</configSections>

<reviewPeriod>

<Periods>

<period id="1" />

<period id="2" name="d" />

<period id="3" name="m" />

</Periods>

</reviewPeriod>

</configuration>

  注意第一个period节点没有定义name属性。.Net Framework中关于程序配置处理的类都在System.Configuration命名空间下,应用很广泛,比如Asp.Net和WCF项目,还有许多第三方框架如NHibernate。下面定义三个类,分别描述自定义节点配置,自定义节点集合,自定义节点实体,这也是最普通的程序自定义配置处理方式。然后就可以遍历ConfigurationManager.GetSection("reviewPeriod") as ReviewPeriod 访问每个period对象。

namespace WordPadTest

{

class ReviewPeriod : ConfigurationSection

{

[ConfigurationProperty("Periods")]

public Periods Periods

{

get { return this["Periods"] as Periods; }

}

}

class Periods: ConfigurationElement
Collection

{

protected override ConfigurationElement CreateNewElement()

{

return new Period();

}

protected override object GetElementKey(ConfigurationElement element)

{

return (element as Period).Id;

}

public override ConfigurationElementCollectionType CollectionType

{

get { return ConfigurationElementCollectionType.BasicMap; }

}

protected override string ElementName

{

get { return "period"; }

}

}

public class Period:ConfigurationElement

{

[ConfigurationProperty("name")]

public string Name

{

get { return (string)this["name"]; }

}

[ConfigurationProperty("id")]

public int Id

{

get { return (int)this["id"]; }

}

}

}

  这段程序运行没问题,意外的是在第一个period节点上,它的Name属性是什么呢,一直以来我都弄错了,可能还有许多人也弄错了。正确答案是String.Empty,而不是null。而且即使我在ConfigurationProperty加上DefaultValue=null,Name返回的依然是String.Empty。

  在我看来,null应该用于表示一种在我们预料之外的状态,包括传入的参数和返回的结果。比如一段从数据库读取记录的代码,如果执行中出现异常,则返回null,和正常执行后未找到任何匹配记录的情况截然不同。同理,对于节点的name属性未定义的情况,显然也不同于定义了name=”"的情况,返回null是合理的。而ConfigurationElement不允许string属性为null,可能有某方面的考虑,但这应该是个Bug,因为它返回值含混不清,是对string空值的误解。

  请再来看另一个例子:如果这个返回值变成了参数的情况。在实际软件中,读取XML数据源时,通常要进行架构验证,比如像下面这样:

XmlReaderSettings settings = new XmlReaderSettings();

settings.Schemas.Add(targetNamespace, "postlist.xsd"); //targetNamespace是传入方法的参数

settings.ValidationType = ValidationType.Schema;

XmlReader reader = XmlReader.Create("postlist.xml", settings);

  这段代码有一个问题,它未判断targetNamespace的是Null还是String.Empty。对于XmlSchemaSet的Add方法,targetNamespace参数如果为null,则表示使用xsd文件中定义的命名空间,而如果传入String.Empty,XmlSchemaSet依然认为,是我们手动指定了一个空的命名空间,而这完全不是我们想要的。

  如果在xsd文件中定义了targetNamespace,我们手动指定的namespace必须与之一致,否则将抛出异常。而xsd文件中的targetNameSpace属性,你可以不加它,但加了就不允许空值。换句话说,我们传入的为String.Empty时targetNameSpace参数时,xsd中只要有targetNamespace的定义,程序必然出错。下图也是上面代码执行的结果,和传null值的情况有天壤之别。

  我们不能怪罪写Xml验证的人太马虎,微软一个内部框架中就有这个问题。归根究底,是.Net Framework对null的误用,导致了我们的误解。

  首先,ConfigurationElement类对返回值的误用,属性值该是null却返回String.Empty。

  其次,XmlSchemaSet类的Add方法有一定问题,应该提供一个重载函数,不需要传入为null的targetNamespace参数,直接用xsd文件中的对应属性。 不但方便,也减少出错的机会。当然,它正确的区分了null和empty的含义,这点还是值得称赞的。

  连.Net Framework对null使用上都有如此的问题,我们写程序时,应该更小心翼翼,对付这个难以捉摸、令人纠结的null。

时间: 2024-07-31 20:52:27

.Net令人纠结的Null的相关文章

一起谈.NET技术,.Net令人纠结的Null

从我们刚学.Net编程起,我们的程序不断被从天而降NullReferenceException打断.直到今天,我们仍然时常为C#的Null或者VB的Nothing困惑.什么情况下我们该返回null,如果参数是null代表什么.许多类型,有两种不同意义的空状态,一种是null,一种是其本身或其某个属性集合中没有元素,这就更容易产生误用.常听有人说,Null这个概念在编程语言中根本不应该存在.但是,从C++到Java到.Net,它从未离开过. 最近,注意到.Net Framework在读取程序配置文

.Net令人纠结的Nu“.NET研究”ll

从我们刚学.Net编程起,我们的程序不断被从天而降NullReferenceException打断.直到今天,我们仍然时常为C#的Null或者VB的Nothing困惑.什么情况下我们该返回null,如果参数是null代表什么.许多类型,有两种不同意义的空状态,一种是null,一种是其本身或其某个属性集合中没有元素,这就更容易产生误用.常听有人说,Null这个概念在编程语言中根本不应该存在.但是,从C++到Java到.Net,它从未离开过. 最近,注意到.Net Framework在读取程序配置文

网络安全:一场令人纠结的持久战

本报记者 张伟报道 针对日益严重的网络安全问题,工业和信息化部部长李毅中日前表示,网络安全要标本兼治,重在治本,目前相关部门正在研究实施手机.网络实名制.对此,网络安全服务提供商的代表们发表了各自不同的看法. 靠技术还是实名制 江民新科技术有限公司策划部总经理曹凌翔向记者表示,技术的问题是永远存在的,因为操作系统和各种网络应用程序可能存在这样那样的未知漏洞,安全厂商永远不可能预知或封堵住所有的安全漏洞,从这种意义上讲,网络也永远不可能百分之百安全. "实行实名制是网络安全有效治本手段之一,在发现

这些令人纠结的百度快照你遇到过吗

  最近的百度的确有些让人捉摸不透,打着整理网络环境的旗号疯狂K站不说,快照也是千奇百怪,不仅自己的网站快照出现了很多问题,朋友的网站也是这样十分蛋疼.不过毕竟是做过几年的网站,对于百度的脾性多少有些了解,所以不会太慌张,可是新手朋友就不好说了,辛辛苦苦做的网站快照说没就没,说有又有,真的挺折磨人的,下面艺星就根据自己的经历来总结一下那些令我们蛋疼的快照,以便让大家尤其是新手朋友有个参考. 快照无缘无故的回档 昨天有一个朋友向我询问,为什么自己的网站坚持天天更新,认真做外链,但是快照却无缘无故得

这费那费收得令人纠结

本报记者 金涛 终结免费午餐, 银行收费如滚雪球 在杭州体育场路上某市级事业单位工作的80后白领史伊萍,是此次ATM机跨行取款 手续费上调的"受害者".工资卡拿的是工行牡丹灵通卡,家门口却是建行.广发银行的营业网点.所以,几乎每个月小史都要在ATM机上跨行取款.涨价后,她每月的手续费多支出了一半.小史说:"说实话,这点手续费还负担得起,但银行说涨就涨,连一声招呼都不打,终归心里有点不舒服."她还表示,自己从ATM机上取款也是为了响应银行的倡导,减少营业窗口排队压力,

主流web容器(jetty,tomcat,jboss)的classloader机制对比和相关问题分析

背景      前段时间一直在做应用容器的迁移,将公司的应用容器从jboss,tomcat统一迁移到jetty.在整个迁移过程中遇到最多的潜在问题还是在classloader机制上,这里记录一下希望能对大家有所帮助,避免重复走弯路.   啥都不说,先来看下遇到的几个问题,比较纠结的问题. 问题1: (jar sealed问题) 1.Caused by: java.lang.SecurityException: sealing violation: package com.sun.media.ja

利用linux信号机制调试段错误(Segment fault)

在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过串口.显示器可以查看消息,只要程序运行,通过GDB调试工具即可捕捉产生segment fault的具体原因.但是不知大家有没有想法,当程序运行在嵌入式设备上时,你所面临资源的缺乏,你没有串口打印信息,没有显示器可查看,你不知道程序运行的状态,如果程序的产生segment falut这种bug发生的周

深入分析jsonp协议原理_json

今天在开发联调的过程中,需要跨域的获取数据,因为使用的jquery,当然使用dataType:'jsonp'就能够很easy的解决了. 但是因为当时后端没有支持jsonp来访问,后来他在实现这个功能的时候问了我一句,jsonp形式返回的格式是怎么样子的?我一直以来只知道怎么使用,迷迷糊糊的却没有答上来... 虽然后来解决了,但是对于喜欢解决问题的我,心里却一直耿耿于怀,必须得把这个研究透彻了,于是我开始翻阅资料,看到后面真有种豁然开朗的感觉,于是打算做个笔记与大家分享. JSON和JSONP的区

毕业生、待业毕业生应该做的几件事

写在前面: 在IT(IT,Information Technology,信息技术,或许有人真的忘了或不知道IT代表什么含义)这个偏向于技术的行业里,聚集着大量的信息技术爱好者.他们相当一部分是年轻的学生或者刚进入社会不久的青年."教育从娃娃抓起",这话一点也不假,而且一直是这么做的.但是很多人(其中还包括一些教育工作者)认为教育是教育者的事而与被教育者关系不大,认为教育者仅仅是传道授业解惑而忽略了他们内心的想法和变化.很多学生在中学时或者在小时候不理解老师或家长告诫自己的话或者强迫要求