.net2.0 自定义配置节 (处理自定义配置文件)
微软的经典案例Duwamishi7中使用自定义配置灵活配置应用程序。在.net2.0中也可以通过自定义的配置元素扩展标准的ASP.NET 配置设置集。但是必须创建自己的配置节处理程序,并且该处理程序必须是一个实现 System.Configuration.ConfigurationSection 的类。
ConfigurationSection类代表一个配置节,在处理自定义配置节时候经常用到的类还包括:用于创建自定义节处理程序的类。
下面是一段处理自定义配置节的代码:
代码中的第一个类MyBookShopConfigurationData就是对自定义配置节的操作类。ReadConnectionString(sting)方法用于从自定义配置节中读取"MyBookShop.DataAccess.ConnectionString"的值。它首先判断在配置文件中有没有"MyBookShopConfiguration"配置节,如果没有则用静态的类常量为默认值添加这个配置节(这一点还是很强悍的,即使配置文件里是空的程序也仍然可以运行!对配置文件的自我修复能力是很好的。),如果有就读取这配置元素的值供应用程序使用。
总结:通过使用自定义的派生类可以操作自定义配置。这即极大的提高了程序的灵活性也可以增强应用程序的健壮性。还可以根据需求添加更复杂的自定义配置节,但是需要相应的根据自定义配置节的结构关系来添加自定义的派生类。这一点可以说是巨大的灵活性和健壮性代给我们的一点繁索的地方。或许还有更好的方式操作自定义配置节,本人就不太清楚了。/
[本文是罗晓个人原创,转载请注明出处!]
ConfigurationSection类代表一个配置节,在处理自定义配置节时候经常用到的类还包括:用于创建自定义节处理程序的类。
下面是一段处理自定义配置节的代码:
public class MyBookShopConfigurationData
{
//
// Constant values for all expected entries in the DuwamishConfiguration section
//
private const String DATAACCESS_CONNECTIONSTRING = "MyBookShop.DataAccess.ConnectionString";
//
// Static member variables. These contain the application settings
// from Config.Web, or the default values.
//
private static String dbConnectionString;
//
// Constant values for all of the default settings.
//
private const String DATAACCESS_CONNECTIONSTRING_DEFAULT = "server=localhost; User ID=user;Password=user;database=MyBookShop";
public static String DbConnectionString
{
get { return MyBookShopConfigurationData.dbConnectionString; }
}
/// <summary>
/// 从指定的配置文件读取数据库连接字符串
/// <remarks>
/// 如果指定的配置文件中没有定义MyBookShopConfiguration节点,或者MyBookShopConfiguration节点中
/// 没有MyBookShop.DataAccess.ConnectionString元素,则用默认的连接字符串创建它们。
/// </remarks>
/// <para>sConfigFilePath:</para>
/// <param name="sConfigFilePath">指定的配置文件路径全名。</param>
/// </summary>
public static void ReadConnectionString(string sConfigFilePath)
{
try
{
MyBookShopConfigurationSection ConfigSection =
ConfigurationManager.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
if (ConfigSection == null) // MyBookShopConfigurationSection.SECTION_NAME配置节点不存在
{
dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
///
/// 添加MyBookShopConfigurationSection.SECTION_NAME配置节点,
/// 并用默认值添加DATAACCESS_CONNECTIONSTRING配置元素
///
// web.configw文件的映射
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = sConfigFilePath;
// Get the current configuration (file).
System.Configuration.Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(fileMap,
ConfigurationUserLevel.None);
MyBookShopConfigurationSection myBookShopConfigSection;
// Create an entry in the <configSections>.
myBookShopConfigSection = new MyBookShopConfigurationSection();
config.Sections.Add(MyBookShopConfigurationSection.SECTION_NAME, myBookShopConfigSection);
config.Save();
// Create the actual target section and write it to
// the configuration file.
myBookShopConfigSection = config.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
myBookShopConfigSection.SectionInformation.ForceSave = true;
myBookShopConfigSection.bookShopConfigCollection.Add(new MyBookShopConfigurationElement(DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT));
config.Save(ConfigurationSaveMode.Full);
}
else
{
MyBookShopConfigurationElement ConnStringElement;
ConnStringElement = ConfigSection.bookShopConfigCollection.GetElementByKey( DATAACCESS_CONNECTIONSTRING );
if (ConnStringElement != null)
{
dbConnectionString = ConnStringElement.Value;
}
else // DATAACCESS_CONNECTIONSTRING配置元素不存在
{
dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
///
/// 用默认值添加DATAACCESS_CONNECTIONSTRING配置元素
///
// web.configw文件的映射
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = sConfigFilePath;
// Get the current configuration (file).
System.Configuration.Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(fileMap,
ConfigurationUserLevel.None);
// Create the actual target section and write it to
// the configuration file.
MyBookShopConfigurationSection myBookShopConfigSection;
myBookShopConfigSection = config.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
myBookShopConfigSection.SectionInformation.ForceSave = true;
myBookShopConfigSection.bookShopConfigCollection.Add(new MyBookShopConfigurationElement(DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT));
config.Save(ConfigurationSaveMode.Full);
}
}
}
catch (Exception e)
{
throw e;
}
}
}
// Define a property section named <MyBookShopConfigurationCollection>
// containing a MyBookShopConfigurationElementCollection collection of
// MyBookShopConfigurationElement elements.
// This section requires the definition of MyBookShopConfigurationElementCollection and
// MyBookShopConfigurationElement types.
public class MyBookShopConfigurationSection : ConfigurationSection
{
public const string SECTION_NAME = "MyBookShopConfiguration";
private const string SECTION_COLLECTION_NAME = "BookShopConfigCollection";
// Declare the collection element.
//MyBookShopConfigurationElement bookShopConfigElement;
public MyBookShopConfigurationSection()
{
// Create a collection element.
// The property values assigned to
// this instance are provided
// by the ConfigurationProperty attributes
// associated wiht the MyBookShopConfigurationElement
// properties.
//bookShopConfigElement = new MyBookShopConfigurationElement();
}
// Declare the urls collection property.
// Note: the "IsDefaultCollection = false" instructs
// .NET Framework to build a nested section of
// the kind <MyBookShopConfigurationGroup> </MyBookShopConfigurationGroup>.
[ConfigurationProperty(SECTION_COLLECTION_NAME, IsDefaultCollection = false)]
[ConfigurationCollection(typeof(MyBookShopConfigurationElementCollection),
AddItemName = "add",
ClearItemsName = "clear",
RemoveItemName = "remove")]
public MyBookShopConfigurationElementCollection bookShopConfigCollection
{
get
{
MyBookShopConfigurationElementCollection bookShopConfigCollection =
(MyBookShopConfigurationElementCollection)base[SECTION_COLLECTION_NAME];
return bookShopConfigCollection;
}
}
}
// Define the MyBookShopConfigurationElementCollection that will contain the MyBookShopConfigurationElement
// elements.
public class MyBookShopConfigurationElementCollection : ConfigurationElementCollection
{
public MyBookShopConfigurationElementCollection()
{
//MyBookShopConfigurationElement bookShopConElement = (MyBookShopConfigurationElement)CreateNewElement();
//Add(bookShopConElement);
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.AddRemoveClearMap;
}
}
protected override ConfigurationElement CreateNewElement()
{
return new MyBookShopConfigurationElement();
}
protected override Object GetElementKey(ConfigurationElement element)
{
return ((MyBookShopConfigurationElement)element).Key;
}
public MyBookShopConfigurationElement this[int index]
{
get
{
return (MyBookShopConfigurationElement)BaseGet(index);
}
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
new public MyBookShopConfigurationElement this[string Name]
{
get
{
return (MyBookShopConfigurationElement)BaseGet(Name);
}
}
public int IndexOf(MyBookShopConfigurationElement bookShopConfigElement)
{
return BaseIndexOf(bookShopConfigElement);
}
public void Add(MyBookShopConfigurationElement bookShopConfigElement)
{
BaseAdd(bookShopConfigElement);
}
protected override void BaseAdd(ConfigurationElement element)
{
BaseAdd(element, false);
}
public void Remove(MyBookShopConfigurationElement bookShopConfigElement)
{
if (BaseIndexOf(bookShopConfigElement) >= 0)
BaseRemove(bookShopConfigElement.Key);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(string name)
{
BaseRemove(name);
}
public void Clear()
{
BaseClear();
}
//---------------------------------------------------------------------
public MyBookShopConfigurationElement GetElementByKey(string sKey)
{
for(int i=0; i<this.Count; i++)
{
if( ((MyBookShopConfigurationElement)this[i]).Key.CompareTo(sKey) == 0)
{
return (MyBookShopConfigurationElement)this[i];
}
}
return null;
}
public MyBookShopConfigurationElement GetElementByValue(string sValue)
{
for (int i = 0; i < this.Count; i++)
{
if (((MyBookShopConfigurationElement)this[i]).Value.CompareTo(sValue) == 0)
{
return (MyBookShopConfigurationElement)this[i];
}
}
return null;
}
//--------------------------------------------------------------------
}
// Define the MyBookShopConfigurationElement for the types contained by the
// MyBookShopConfigurationSection.
public class MyBookShopConfigurationElement : ConfigurationElement
{
public MyBookShopConfigurationElement(String key, String value)
{
this.Key = key;
this.Value = value;
}
public MyBookShopConfigurationElement()
{
}
[ConfigurationProperty("key", DefaultValue = "", IsRequired = true, IsKey = true)]
public string Key
{
get
{
return (string)this["key"];
}
set
{
this["key"] = value;
}
}
[ConfigurationProperty("value", DefaultValue = "", IsRequired = true)]
//[RegexStringValidator(@"\w+:\/\/[\w.]+\S*")]
public string Value
{
get
{
return (string)this["value"];
}
set
{
this["value"] = value;
}
}
}
上面的第二个类MyBookShopConfigurationSection就是自定义配置节的自定义处理程序。它有一个MyBookShopConfigurationElementCollection类型的属性,这个属性代表自定义配置节中包含的配置元素集合。而MyBookShopConfigurationElement类代表的就是自定义配置节中的单个配置元素了。MyBookShopConfigurationSection处理的自定义配置节的结构如下(<MyBookShopConfiguration>节):{
//
// Constant values for all expected entries in the DuwamishConfiguration section
//
private const String DATAACCESS_CONNECTIONSTRING = "MyBookShop.DataAccess.ConnectionString";
//
// Static member variables. These contain the application settings
// from Config.Web, or the default values.
//
private static String dbConnectionString;
//
// Constant values for all of the default settings.
//
private const String DATAACCESS_CONNECTIONSTRING_DEFAULT = "server=localhost; User ID=user;Password=user;database=MyBookShop";
public static String DbConnectionString
{
get { return MyBookShopConfigurationData.dbConnectionString; }
}
/// <summary>
/// 从指定的配置文件读取数据库连接字符串
/// <remarks>
/// 如果指定的配置文件中没有定义MyBookShopConfiguration节点,或者MyBookShopConfiguration节点中
/// 没有MyBookShop.DataAccess.ConnectionString元素,则用默认的连接字符串创建它们。
/// </remarks>
/// <para>sConfigFilePath:</para>
/// <param name="sConfigFilePath">指定的配置文件路径全名。</param>
/// </summary>
public static void ReadConnectionString(string sConfigFilePath)
{
try
{
MyBookShopConfigurationSection ConfigSection =
ConfigurationManager.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
if (ConfigSection == null) // MyBookShopConfigurationSection.SECTION_NAME配置节点不存在
{
dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
///
/// 添加MyBookShopConfigurationSection.SECTION_NAME配置节点,
/// 并用默认值添加DATAACCESS_CONNECTIONSTRING配置元素
///
// web.configw文件的映射
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = sConfigFilePath;
// Get the current configuration (file).
System.Configuration.Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(fileMap,
ConfigurationUserLevel.None);
MyBookShopConfigurationSection myBookShopConfigSection;
// Create an entry in the <configSections>.
myBookShopConfigSection = new MyBookShopConfigurationSection();
config.Sections.Add(MyBookShopConfigurationSection.SECTION_NAME, myBookShopConfigSection);
config.Save();
// Create the actual target section and write it to
// the configuration file.
myBookShopConfigSection = config.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
myBookShopConfigSection.SectionInformation.ForceSave = true;
myBookShopConfigSection.bookShopConfigCollection.Add(new MyBookShopConfigurationElement(DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT));
config.Save(ConfigurationSaveMode.Full);
}
else
{
MyBookShopConfigurationElement ConnStringElement;
ConnStringElement = ConfigSection.bookShopConfigCollection.GetElementByKey( DATAACCESS_CONNECTIONSTRING );
if (ConnStringElement != null)
{
dbConnectionString = ConnStringElement.Value;
}
else // DATAACCESS_CONNECTIONSTRING配置元素不存在
{
dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
///
/// 用默认值添加DATAACCESS_CONNECTIONSTRING配置元素
///
// web.configw文件的映射
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = sConfigFilePath;
// Get the current configuration (file).
System.Configuration.Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(fileMap,
ConfigurationUserLevel.None);
// Create the actual target section and write it to
// the configuration file.
MyBookShopConfigurationSection myBookShopConfigSection;
myBookShopConfigSection = config.GetSection(MyBookShopConfigurationSection.SECTION_NAME) as MyBookShopConfigurationSection;
myBookShopConfigSection.SectionInformation.ForceSave = true;
myBookShopConfigSection.bookShopConfigCollection.Add(new MyBookShopConfigurationElement(DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT));
config.Save(ConfigurationSaveMode.Full);
}
}
}
catch (Exception e)
{
throw e;
}
}
}
// Define a property section named <MyBookShopConfigurationCollection>
// containing a MyBookShopConfigurationElementCollection collection of
// MyBookShopConfigurationElement elements.
// This section requires the definition of MyBookShopConfigurationElementCollection and
// MyBookShopConfigurationElement types.
public class MyBookShopConfigurationSection : ConfigurationSection
{
public const string SECTION_NAME = "MyBookShopConfiguration";
private const string SECTION_COLLECTION_NAME = "BookShopConfigCollection";
// Declare the collection element.
//MyBookShopConfigurationElement bookShopConfigElement;
public MyBookShopConfigurationSection()
{
// Create a collection element.
// The property values assigned to
// this instance are provided
// by the ConfigurationProperty attributes
// associated wiht the MyBookShopConfigurationElement
// properties.
//bookShopConfigElement = new MyBookShopConfigurationElement();
}
// Declare the urls collection property.
// Note: the "IsDefaultCollection = false" instructs
// .NET Framework to build a nested section of
// the kind <MyBookShopConfigurationGroup> </MyBookShopConfigurationGroup>.
[ConfigurationProperty(SECTION_COLLECTION_NAME, IsDefaultCollection = false)]
[ConfigurationCollection(typeof(MyBookShopConfigurationElementCollection),
AddItemName = "add",
ClearItemsName = "clear",
RemoveItemName = "remove")]
public MyBookShopConfigurationElementCollection bookShopConfigCollection
{
get
{
MyBookShopConfigurationElementCollection bookShopConfigCollection =
(MyBookShopConfigurationElementCollection)base[SECTION_COLLECTION_NAME];
return bookShopConfigCollection;
}
}
}
// Define the MyBookShopConfigurationElementCollection that will contain the MyBookShopConfigurationElement
// elements.
public class MyBookShopConfigurationElementCollection : ConfigurationElementCollection
{
public MyBookShopConfigurationElementCollection()
{
//MyBookShopConfigurationElement bookShopConElement = (MyBookShopConfigurationElement)CreateNewElement();
//Add(bookShopConElement);
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.AddRemoveClearMap;
}
}
protected override ConfigurationElement CreateNewElement()
{
return new MyBookShopConfigurationElement();
}
protected override Object GetElementKey(ConfigurationElement element)
{
return ((MyBookShopConfigurationElement)element).Key;
}
public MyBookShopConfigurationElement this[int index]
{
get
{
return (MyBookShopConfigurationElement)BaseGet(index);
}
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
new public MyBookShopConfigurationElement this[string Name]
{
get
{
return (MyBookShopConfigurationElement)BaseGet(Name);
}
}
public int IndexOf(MyBookShopConfigurationElement bookShopConfigElement)
{
return BaseIndexOf(bookShopConfigElement);
}
public void Add(MyBookShopConfigurationElement bookShopConfigElement)
{
BaseAdd(bookShopConfigElement);
}
protected override void BaseAdd(ConfigurationElement element)
{
BaseAdd(element, false);
}
public void Remove(MyBookShopConfigurationElement bookShopConfigElement)
{
if (BaseIndexOf(bookShopConfigElement) >= 0)
BaseRemove(bookShopConfigElement.Key);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(string name)
{
BaseRemove(name);
}
public void Clear()
{
BaseClear();
}
//---------------------------------------------------------------------
public MyBookShopConfigurationElement GetElementByKey(string sKey)
{
for(int i=0; i<this.Count; i++)
{
if( ((MyBookShopConfigurationElement)this[i]).Key.CompareTo(sKey) == 0)
{
return (MyBookShopConfigurationElement)this[i];
}
}
return null;
}
public MyBookShopConfigurationElement GetElementByValue(string sValue)
{
for (int i = 0; i < this.Count; i++)
{
if (((MyBookShopConfigurationElement)this[i]).Value.CompareTo(sValue) == 0)
{
return (MyBookShopConfigurationElement)this[i];
}
}
return null;
}
//--------------------------------------------------------------------
}
// Define the MyBookShopConfigurationElement for the types contained by the
// MyBookShopConfigurationSection.
public class MyBookShopConfigurationElement : ConfigurationElement
{
public MyBookShopConfigurationElement(String key, String value)
{
this.Key = key;
this.Value = value;
}
public MyBookShopConfigurationElement()
{
}
[ConfigurationProperty("key", DefaultValue = "", IsRequired = true, IsKey = true)]
public string Key
{
get
{
return (string)this["key"];
}
set
{
this["key"] = value;
}
}
[ConfigurationProperty("value", DefaultValue = "", IsRequired = true)]
//[RegexStringValidator(@"\w+:\/\/[\w.]+\S*")]
public string Value
{
get
{
return (string)this["value"];
}
set
{
this["value"] = value;
}
}
}
<?xml version="1.0"?>
<!--
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“Asp.Net 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
\Windows\Microsoft.Net\Framework\v2.x\Config 中
-->
<configuration>
<configSections>
<section name="MyBookShopConfiguration" type="MyBookShop.Common.MyBookShopConfigurationSection, Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>
<MyBookShopConfiguration>
<BookShopConfigCollection>
<clear />
<add key="MyBookShop.DataAccess.ConnectionString" value="server=localhost; User ID=user;Password=user;database=MyBookShop" />
</BookShopConfigCollection>
</MyBookShopConfiguration>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
设置 compilation debug="true" 将调试符号插入
已编译的页面中。但由于这会
影响性能,因此只在开发过程中将此值
设置为 true。
-->
<compilation debug="true"/>
<!--
通过 <authentication> 节可以配置 ASP.NET 使用的
安全身份验证模式,
以标识传入的用户。
-->
<authentication mode="Windows"/>
<!--
如果在执行请求的过程中出现未处理的错误,
则通过 <customErrors> 节可以配置相应的处理步骤。具体说来,
开发人员通过该节可以配置
要显示的 html 错误页
以代替错误堆栈跟踪。
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>
通过这几个类与配置节各元素的对应关系,就可以操所自定义配置节了。<!--
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“Asp.Net 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
\Windows\Microsoft.Net\Framework\v2.x\Config 中
-->
<configuration>
<configSections>
<section name="MyBookShopConfiguration" type="MyBookShop.Common.MyBookShopConfigurationSection, Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>
<MyBookShopConfiguration>
<BookShopConfigCollection>
<clear />
<add key="MyBookShop.DataAccess.ConnectionString" value="server=localhost; User ID=user;Password=user;database=MyBookShop" />
</BookShopConfigCollection>
</MyBookShopConfiguration>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
设置 compilation debug="true" 将调试符号插入
已编译的页面中。但由于这会
影响性能,因此只在开发过程中将此值
设置为 true。
-->
<compilation debug="true"/>
<!--
通过 <authentication> 节可以配置 ASP.NET 使用的
安全身份验证模式,
以标识传入的用户。
-->
<authentication mode="Windows"/>
<!--
如果在执行请求的过程中出现未处理的错误,
则通过 <customErrors> 节可以配置相应的处理步骤。具体说来,
开发人员通过该节可以配置
要显示的 html 错误页
以代替错误堆栈跟踪。
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>
代码中的第一个类MyBookShopConfigurationData就是对自定义配置节的操作类。ReadConnectionString(sting)方法用于从自定义配置节中读取"MyBookShop.DataAccess.ConnectionString"的值。它首先判断在配置文件中有没有"MyBookShopConfiguration"配置节,如果没有则用静态的类常量为默认值添加这个配置节(这一点还是很强悍的,即使配置文件里是空的程序也仍然可以运行!对配置文件的自我修复能力是很好的。),如果有就读取这配置元素的值供应用程序使用。
总结:通过使用自定义的派生类可以操作自定义配置。这即极大的提高了程序的灵活性也可以增强应用程序的健壮性。还可以根据需求添加更复杂的自定义配置节,但是需要相应的根据自定义配置节的结构关系来添加自定义的派生类。这一点可以说是巨大的灵活性和健壮性代给我们的一点繁索的地方。或许还有更好的方式操作自定义配置节,本人就不太清楚了。/
[本文是罗晓个人原创,转载请注明出处!]