【IT168 技术文档】从我们刚学.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>
<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"]; }
}
}
}
{
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"]; }
}
}
}