今天有需要写个配置类,在实现过程中遇到了一个系统异常。终于,今天这个异常让我有机会好好表明一下使用微软的开发环境所存在的困惑。
故障是这样的,先看一下下面的代码:
1 public class CroplandSection : ConfigurationSection
2 {
3
4 [ConfigurationProperty("Name", DefaultValue = "Cropland", IsRequired = true)]
5 [StringValidator(MinLength = 0, MaxLength = 15)]
6 public string Name
7 {
8 get { return (string)base["Name"]; }
9 }
10
11 [ConfigurationProperty("Age", DefaultValue = 23, IsRequired = true)]
12 [IntegerValidator(MinValue = 1, MaxValue = 99)]//如果指定了验证范围则必需在ConfigurationProperty特性中指明默认值,否则运行时报异常
13 public int Age
14 {
15 get { return (int)base["Age"]; }
16 }
17
18 [ConfigurationProperty("Address",DefaultValue ="DefaultValue", IsRequired = true)]
19 //[CallbackValidator(CallbackMethodName = "AddressValidator", Type = typeof(ConfiongrationExten.CroplandSection))]
20 [AddressValidatorAttribe("address")]
21 public string Address
22 {
23 get { return (string)base["Address"]; }
24 }
25
26 public static void AddressValidator(object address)
27 {
28 //实始时这里会被执行两次,默认值一次,配置文件中的一次
29 string a = address.ToString();
30 Console.WriteLine("CallBack:"+address);
31
32 }
33 }
2 {
3
4 [ConfigurationProperty("Name", DefaultValue = "Cropland", IsRequired = true)]
5 [StringValidator(MinLength = 0, MaxLength = 15)]
6 public string Name
7 {
8 get { return (string)base["Name"]; }
9 }
10
11 [ConfigurationProperty("Age", DefaultValue = 23, IsRequired = true)]
12 [IntegerValidator(MinValue = 1, MaxValue = 99)]//如果指定了验证范围则必需在ConfigurationProperty特性中指明默认值,否则运行时报异常
13 public int Age
14 {
15 get { return (int)base["Age"]; }
16 }
17
18 [ConfigurationProperty("Address",DefaultValue ="DefaultValue", IsRequired = true)]
19 //[CallbackValidator(CallbackMethodName = "AddressValidator", Type = typeof(ConfiongrationExten.CroplandSection))]
20 [AddressValidatorAttribe("address")]
21 public string Address
22 {
23 get { return (string)base["Address"]; }
24 }
25
26 public static void AddressValidator(object address)
27 {
28 //实始时这里会被执行两次,默认值一次,配置文件中的一次
29 string a = address.ToString();
30 Console.WriteLine("CallBack:"+address);
31
32 }
33 }
在Age属性中我开始没有指定DefaultValue是多少,但我指定了其取值范围1~100,然后我就开始编译调试。一启动就报出异常:“属性“Age”的值无效。错误为: 该值必须在 1-99 范围内。”
稍等,请看我配置文件里的内容:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name ="Cropland" type ="ConfiongrationExten.CroplandSection,ConfiongrationExten"/>
</configSections>
<Cropland
Name ="Cropland"
Address="keji4Rd."
Age="39"
/>
</configuration>
<configuration>
<configSections>
<section name ="Cropland" type ="ConfiongrationExten.CroplandSection,ConfiongrationExten"/>
</configSections>
<Cropland
Name ="Cropland"
Address="keji4Rd."
Age="39"
/>
</configuration>
Age为39,并没有超出上面所要求的范围限制啊。奇怪吧,我想了好久调了好久甚至我把Age换成别的字符也不行。没办法我从别处找了一个配置类看了看区别为它添加上了DefaultValue=23,这一回好了没有报错,但原因还没有找到。先不管,继续。
看上面类代码的最后一个方法
1 public static void AddressValidator(object address)
2 {
3 //实始时这里会被执行两次,默认值一次,配置文件中的一次
4 string a = address.ToString();
5 Console.WriteLine("CallBack:"+address);
6 }
2 {
3 //实始时这里会被执行两次,默认值一次,配置文件中的一次
4 string a = address.ToString();
5 Console.WriteLine("CallBack:"+address);
6 }
这里面第次启动的时候都会被调用两次,我很纳闷为什么会被调用两次呢?
想了一阵才让我恍然大悟,也随即明白了刚才第一个古怪问题的答案来了,看了我下面的表述过程你也就明白了。
.Net的处理过程是这样的:
1、执行时先加载默认值,并在加载时验证默认值;
2、加载配置文件里配置的值,并在加载时验证;
3、如果有配置值则用配置值覆盖默认值。
这下就清楚了它为什么在指定了验证而没有配置默认值的时候会报异常,而且报的异常又似乎与实际情况不太相及:没有配置默认值(或系统需要默认值),而报出的异常却是属性“Age”的值无效。错误为: 该值必须在 1-99 范围内。”
但如果搞明白了它的处理过程就很理解它这样报了。不过有多少人在使用一个产品的时候需要仔细的了解它的内部处理过程呢?类封装的目的不也是以提供标准接交互接口的方式对外提供服务而尽量对外忽略它的内部处理过程吗?
我想类假这种问题才是真真正正影响在这个平台上做开发的人吧。其实有异常不可怕,问题也困难也是能解决的。但让人恼火的就是这种表面上明明没有问题确给你报出问题的情况来。比如这件事中按系统报出的异常:属性“Age”的值无效。错误为: 该值必须在 1-99 范围内。”。我检查了代码又检查了配置文件明明没有问题啊,但系统就是报出这样的异常来,而且还一幅不容置疑的样子。
这个问题的解答才让我明白为什么有那么多的开发人员不喜欢看微软的MSDN,抱怨MSDN里面讲的答非所问、语无论次了。