一起谈.NET技术,.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: ConfigurationElementCollection
{
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:28

一起谈.NET技术,.Net令人纠结的Null的相关文章

.Net令人纠结的Null

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

一起谈.NET技术,引用类型赋值为null与加速垃圾回收

在标准的Dispose模式中,提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要. 有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾.其他人则认为这没有任何帮助.是否赋值为null的问题首先在方法的内部被人提起.现在,为了更好的阐述提出的问题,我们来撰写一个Winform窗体应用程序.如下: private void button1_Click(object sender, EventArgs e) { Method1(); Method2(); } pr

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

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

《创业家》牛文文:少谈点模式多谈点技术

"模式"如同当年的"主义",流行于各种创业大赛.创业励志节目.论坛的"街头"式秀场 文/创业家 牛文文 "美国某某公司你知道吧?就是刚被戴尔.惠普.思科十几亿美元抢购的那家.我们的模式和它的一样,现在还没赢利,可将来起码有十几亿人民币的市值." "我开了小煤矿,但煤运不出去,上商学院之后受到启发,想搞模式创新,具体讲就是想在铁路边上搞个煤炭物流开发区,建一个大的物流和信息流平台,把分散的煤炭集中在我这个园区,这样和铁

谈微博:数次纠结想关闭它

姚晨 微博红人.联合国难民署http://www.aliyun.com/zixun/aggregation/1459.html">中国区代言人.时尚明星围绕在姚晨身上的各种名头和光环,似乎掩盖了她本职身份演员.最近,姚晨在陈凯歌导演新片<搜索>中,饰演记者陈若兮一角,以演员身份重回公众视野.近日,有媒体专访了演员姚晨,和她展开深入对谈.谈及自己"微博女王"的身份时,姚晨坦言2000万微博粉丝是围观者而非真粉丝,自己曾数次纠结想关闭微博.而谈到表演:姚晨表示至

一起谈.NET技术,走向ASP.NET架构设计——第一章:走向设计

前言:很多做开发的人都在不断的摸索着,积极的学习,试图找出一条走向架构设计的成功法则.每当有人问起我们的职业,我们也常常在说:"软件设计".有时,我就在想:"设计",这个已经被我们嚼烂了的词,到底有多少人真正懂"设计"的含义. 自动进入IT,走在开发这条路上,就一直在不断的摸索,寻找,苦思:如何能够才能成为架构师.于是在网络上不断的收集和阅读架构设计方面的书籍和资料,到处在找一些架构师的传记,文章和甚至是采访资料..... 同时一直不断的请教自己

一起谈.NET技术,谈谈微软技术,以及对待技术应有的态度

昨晚在家上网,看看微软研究院TechFest 2010的消息,逛逛Channel 9,瞅瞅DevLabs里的项目,以及F#与Reactive Framework之类东西.然而,我一边对那些有趣而奇妙的技术感叹不已,同时却又产生出一种忿忿之情.为什么?因为在国内的技术圈子里,经常有一种在我看来莫名奇妙的鄙视微软技术的风气.这样的风气在国内的推特圈里也非常明显,基本上只有我一个人对微软的技术抱有好感,并"勇于"和大量意见向左的人争辩.忿忿之余,我便在推特上不断表达我对这种风气的抱怨及否定,

《Java特种兵》1.7 面对技术,我们纠结的那些事儿

1.7 面对技术我们纠结的那些事儿 人生需要面对很多纠结我们都是在纠结中磨练自我意志的. 纠结容易让人浮躁容易让人犯错但是纠结同样会让人成长纠结是黎明前的黑暗. 学会将纠结化作成长的力量在逆境中能生存的强者才是真正的"老A级程序员". 1.7.1 为什么我这里好用那里不好用 "为什么我这里好用那里不好用" 小鬼你是不是经常说这句话如果是那你"中标"了. 你怎么知道我经常这么说呀 这句话要么是老鸟说要么是小鸟说同一句话老鸟说的意思和小鸟的得意思完全

老网工: 浅谈SDN技术的部署和未来

进入2017年,基于SDN的解决方案再次成为最热门的话题之一, 从运营商.到OTT再到大的企业都已经开始大谈SDN网络规划和部署,甚至WannaCry蠕虫爆发时有人谈到利用SDN的方法抵御.但是由于SDN的特殊性和网络具体环境的复杂性,不同客户SDN的部署实际上千差万别,作为从事网络领域20年的老网工深深感受到SDN与传统网络的巨大变化,在这里和大家分享一下SDN的部署经验和艰辛,抛砖引玉谈谈个人体会. 首先声明一点,今天讨论的SDN不再局限于传统的狭义SDN,传统的狭义SDN(基于Openfl