现在我们可以专注于configuationrecord的具体实现了,load方法中得到一个xmltextwriter,并执行.scanfactoriesrecursive和scansectionsrecursive方法。
scanfactoriesrecursive方法会调用他的一个重载方法来解析<configsections>中的<sectiongroup>,<section>,<remove>,<clear>,我们写配置文件时大小写可不能写错哦,.net没有做toslower之类的转换,直接就是 “== “。在这个方法里程序会将解析得到的sectiongroup以key=tagkey,value= ConfigurationRecord.GroupSingleton的方式存到EnsureFactories里,将section以key=tagkey,value=typestring的方式储存,值得注意的是,这里并没有创建实现IConfigurationSectionHandler的实例对象,而是将其类型名(比如:字符串”system.Configuration.NameValueSectionHandler”)作为值到EnsureFactories,等到后面GetConfig的时候再来反射创建。<remove>则存为ConfigurationRecord.RemovedFactorySingleton。<clear>就清空EnsureFactories。这里的tagkey是各级name的组合,比如”mygroup/mysection”这样以分隔符”/”组合的形式。应该客观地说这部分代码用了很多goto语句,可读性不是太好,但这样写也确实没有什么问题。
this.CheckRequiredAttribute(text3, "name", reader);
this.CheckRequiredAttribute(text4, "type", reader);
this.VerifySectionName(text3, reader);
string text5 = ConfigurationRecord.TagKey(configKey, text3);
if (this.HaveFactory(text5) != ConfigurationRecord.HaveFactoryEnum.NotFound)
{
objArray1 = new object[] { text3 } ;
throw this.BuildConfigError(SR.GetString("Tag_name_already_defined", objArray1), reader);
}
this.EnsureFactories[text5] = text4;
goto Label_02B6;
scansectionsrecursive方法会解析配置文件里的section实例,并将其tagkey储存到hashtable _unevaluatedSections中,表示尚未evaluated的configkey的集合,可见section实例对象的创建和handler一样,都是fetch when need。在后面的操作Getconfig中会使用他。
if (this._unevaluatedSections == null)
{
this._unevaluatedSections = new Hashtable();
}
this._unevaluatedSections[text2] = null;
现在我们就可以看getconfig方法是怎么来执行得到我们想要的对象的。
public object GetConfig(string configKey)
{
if (this._error != null)
{
throw this._error;
}
if (this._results.Contains(configKey))
{
return this._results[configKey];
}
object obj1 = this.ResolveConfig(configKey);
lock (this._results.SyncRoot)
{
this._results[configKey] = obj1;
}
return obj1;
}
如果_result中有对应configkey的section实例,就返回,没有则需要对configkey进行resolveconfig,将解析到的对象保存到_result中并返回给用户。在resolveconfig方法中,可以看到如果当前的配置文件中没有要求的configkey就会返回父级的section实例,比如machine.config里的内容。
public object ResolveConfig(string configKey)
{
Hashtable hashtable1 = this._unevaluatedSections;
if ((hashtable1 != null) && hashtable1.Contains(configKey))
{
return this.Evaluate(configKey);
}
if (this._parent != null)
{
return this._parent.GetConfig(configKey);
}
return null;
}
然后就是evaluate及其后续操作了,主要就是将configkey分解成字符串数组,一层层地去找对应的xmlelement,找到后传给configkey对应的handler,如果该handler没有创建则反射创建,然后由该handler创建section的实例对象,返回给用户,该部分关键代码如下:
ConfigXmlDocument document1 = new ConfigXmlDocument();
document1.LoadSingleElement(this._filename, reader);
config = factory.Create(config, null, document1.DocumentElement);
现在我们就明白了当我们用system..configurtion.configuationsetting.getconfig的时候发生过什么了。
在下一篇文章中,我会对系统内置的具体section的handler的实现做详细的阐述。