简单的 XML 配置文件读/写器






2.25/5 (5投票s)
一个非常容易使用的 .NET 配置文件读/写器。
背景
我经常看到开发人员实现他们自己的 XML 配置读/写器版本,这可能需要时间和精力进行开发和维护。 尽管 .NET 2.0 提供了一个配置库,但我还没有看到它被广泛使用。
配置是没有人有一个明确和一致的方法的一个方面。 根据我的经验,我看到大多数开发人员实现他们自己的代码版本来存储/访问配置(这可能在数据库、XML 文件、INI 文件或注册表中)。
在这个示例中,我提出了一个非常基本的 XML 配置文件,整个示例应用程序都基于它,并且我相信它会非常容易使用。 您可以随时扩展配置文件/示例应用程序以满足您的需求,或者使用数据库而不是 XML 等,但我认为这个示例应该足以让您入门,并且将帮助您更容易地维护访问配置文件的代码。
简单的想法
嗯,这不是一个开创性的示例应用程序,但就像我提到的,它可能有助于开发人员理解和重用组件。 此外,由于此应用程序使用反射、自定义属性和 LINQ,我想这将是一个很好的示例练习,以了解初学者级别的概念。
所以,在我们开始之前,这是示例配置文件的样子
<Configuration>
<Module Name="Application-A">
<Section Name="Section-A">
<Entry Name="RefreshRate">11</Entry>
</Section>
</Module>
<Module Name="Application-B">
<Section Name="Section-B">
<Entry Name="LogFile">SomeLogFile.Log</Entry>
</Section>
</Module>
</Configuration>
配置存储在Module
和 Section
内,作为一个 Entry
标签。
我将很快描述如何加载和保存文件,但在此之前,让我们讨论如何检索和保存配置变量。
XML 标签,即 Module
、Section
和 Entry
,被映射到枚举值,因此它们易于读取和写入,类似于属性字段。 这是通过我们附加到每个枚举值的自定义属性来实现的。 自定义属性采用应用程序、Section
标签和 Entry
标签的各自名称,它们与该名称相关; 例如,下面示例中的 RefreshRate
枚举值。
public enum Confiugration
{
[CustomConfig(ApplicationName = "Application-A",
SectionName = "Section-A",
EntryName = "RefreshRate",
DefaultValue = "5")]
RefreshRate,
[CustomConfig(ApplicationName = "Application-B",
SectionName = "Section-B",
EntryName = "LogFile")]
LogFile
};
这允许我们使用以下代码读取配置
configHelper.GetConfigEntry(Configuration.RefreshRate);
类似地,您可以使用以下代码保存配置值
configHelper.SetConfigEntry(Confiugration.RefreshRate, "11");
这是所需的五行自定义属性代码
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class CustomConfigAttribute : Attribute
{
public String ApplicationName { get; set; }
public String SectionName { get; set; }
public String EntryName { get; set; }
public String DefaultValue { get; set; }
}
简而言之,您不必实现任何代码来读取或写入变量; 您所要做的就是为您的配置创建一个枚举,并填写附加到枚举值的适当属性值,并让 CustomConfigHelper
类为您读取和写入配置条目。
我确信您一定很清楚 CustomConfigHelper
类提供了读取附加到枚举值的属性的函数,并根据需要读取/更新配置文件。
为了读取附加到枚举的自定义属性,CustomConfigHelper
类使用反射来处理您传递的枚举。 例如,对于 GetConfigEntry
函数,我们会这样做
public String GetConfigEntry(Enum enumValue)
{
Type type = enumValue.GetType();
FieldInfo info = type.GetField(enumValue.ToString());
var customAttribute = Attribute.GetCustomAttribute(info,
typeof(CustomConfigAttribute)) as CustomConfigAttribute;
一旦检索到自定义属性,我们就可以使用 LINQ 从 xml 文件中检索适当的条目。 为了加载 xml 文件,我们使用 XElement.Load 函数
if (File.Exists(fileName))
{
rootNode = XElement.Load(fileName);
var item = from applicationNode in rootNode.Elements("Module")
where (String)applicationNode.Attribute("Name") ==
customAttribute.ApplicationName
from sectionNode in applicationNode.Elements("Section")
where (String)sectionNode.Attribute("Name") ==
customAttribute.SectionName
from entryNode in sectionNode.Elements("Entry")
where (String)entryNode.Attribute("Name") ==
customAttribute.EntryName
select entryNode.FirstNode;
if (item.Any())
{
return item.First().ToString();
}
}
类似地,我们也可以保存配置
var item = from applicationNode in rootNode.Elements("Module")
where (String) applicationNode.Attribute("Name") ==
customAttribute.ApplicationName
from sectionNode in applicationNode.Elements("Section")
where (String) sectionNode.Attribute("Name") ==
customAttribute.SectionName
from entryNode in sectionNode.Elements("Entry")
where (String) entryNode.Attribute("Name") ==
customAttribute.EntryName
select entryNode;
if(!item.Any())
{
return;
}
item.First().Value = entryValue;
关注点
这是 CustomConfigHelper
类的完整代码,它可以为您完成神奇的事情
public class CustomConfigHelper
{
private static XElement rootNode;
private CustomConfigHelper(){}
private static String configFileName { get; set; }
public CustomConfigHelper(String fileName)
{
if (File.Exists(fileName))
{
rootNode = XElement.Load(fileName);
configFileName = fileName;
}
}
private static void SaveConfigFile(String fileName)
{
rootNode.Save(fileName);
}
public String GetConfigEntry(Enum enumValue)
{
Type type = enumValue.GetType();
FieldInfo info = type.GetField(enumValue.ToString());
var customAttribute = Attribute.GetCustomAttribute(info,
typeof(CustomConfigAttribute)) as CustomConfigAttribute;
return customAttribute == null ? String.Empty :
GetConfigEntry(customAttribute);
}
public void SetConfigEntry(Enum enumValue, String entryValue)
{
if(entryValue == null)
{
entryValue = String.Empty;
}
Type type = enumValue.GetType();
FieldInfo info = type.GetField(enumValue.ToString());
var customAttribute = Attribute.GetCustomAttribute(info,
typeof(CustomConfigAttribute)) as CustomConfigAttribute;
SetConfigEntry(customAttribute, entryValue);
}
private static String GetConfigEntry(CustomConfigAttribute attribute)
{
if (rootNode == null)
{
return attribute.DefaultValue ?? String.Empty;
}
var item = from applicationNode in rootNode.Elements("Module")
where (String)applicationNode.Attribute("Name") ==
attribute.ApplicationName
from sectionNode in applicationNode.Elements("Section")
where (String)sectionNode.Attribute("Name") ==
attribute.SectionName
from entryNode in sectionNode.Elements("Entry")
where (String)entryNode.Attribute("Name") ==
attribute.EntryName
select entryNode.FirstNode;
if (item.Any())
{
return item.First().ToString();
}
return attribute.DefaultValue ?? String.Empty;
}
private static void SetConfigEntry(CustomConfigAttribute attribute,
String entryValue)
{
if (rootNode == null)
{
return;
}
var item = from applicationNode in rootNode.Elements("Module")
where (String) applicationNode.Attribute("Name") ==
attribute.ApplicationName
from sectionNode in applicationNode.Elements("Section")
where (String) sectionNode.Attribute("Name") ==
attribute.SectionName
from entryNode in sectionNode.Elements("Entry")
where (String) entryNode.Attribute("Name") ==
attribute.EntryName
select entryNode;
if(!item.Any())
{
return;
}
item.First().Value = entryValue;
SaveConfigFile(configFileName);
}
}
我希望这有帮助。 一如既往,欢迎提出意见和建议。 干杯。
历史
原始版本。