Cfg-NET






4.89/5 (27投票s)
一种 .NET 配置处理器的替代方案
引言
这是一个 开源 的 .NET 配置处理器,已获得 Apache 2 许可。
配置
- 可由最终用户编辑
- 减少重新编译的需要
- 可与其他配置共存
一个配置处理器
- 易于使用
- 支持集合
- 验证并报告错误和警告
- 提供对
null
的保护 - 允许您将配置存储在任何您想要的位置(例如:Web、文件、字符串)
- 可扩展
- 可组合
- 小巧(约 67 KB)
- 零依赖
- 可移植(.NETStandard1.0,兼容 PCL)
- 可在 Nuget 上找到
配置
开箱即用,Cfg-NET 支持 XML 和 JSON 配置。
XML 示例
<cfg> <fruit> <add name="apple"> <colors> <add name="red" /> <add name="yellow" /> <add name="green" /> </colors> </add> <add name="banana"> <colors> <add name="yellow" /> </colors> </add> </fruit> </cfg>
或者,如果您更喜欢 JSON
{ "fruit": [ { "name":"apple", "colors": [ {"name":"red"}, {"name":"yellow"}, {"name":"green"} ] }, { "name":"banana", "colors": [ {"name":"yellow"} ] } ] }
代码
在代码中,您希望处理一个与之对应的 C# 模型,如下所示
using System.Collections.Generic; class Cfg { public List<Fruit> Fruit { get; set; } } class Fruit { public string Name { get; set; } public List<Color> Colors {get; set;} } class Color { public string Name {get; set;} }
为了让上述模型与 Cfg-NET 一起工作,请让每个类继承 CfgNode
并用 Cfg
自定义属性装饰属性
using System.Collections.Generic; using Cfg.Net; class Cfg : CfgNode { [Cfg] public List<Fruit> Fruit { get; set; } } class Fruit : CfgNode { [Cfg] public string Name { get; set; } [Cfg] public List<Color> Colors {get; set;} } class Color : CfgNode { [Cfg] public string Name {get; set;} }
设计配置
继承 CfgNode
会为您提供 Load
、Check
和 Serialize
方法。
Cfg
属性添加了验证和修改说明。一个属性具有以下内置选项
value
,例如默认值toLower
或toUpper
trim
、trimStart
或trimEnd
required
unique(唯一)
domain
(域),具有delimiter
(分隔符)和ignoreCase
(忽略大小写)选项minLength
(最小长度)和/或maxLength
(最大长度)minValue
(最小值)和/或maxValue
(最大值)
如果我们想确保在我们的配置中定义了某些水果,我们会像这样向水果列表添加 required=true
class Cfg : CfgNode { [Cfg(required=true)] // THERE MUST BE SOME FRUIT! public List<Fruit> Fruit { get; set; } }
如果我们想确保水果名称是唯一的,我们可以像这样向水果名称属性添加 unique=true
class Fruit : CfgNode { [Cfg(unique=true)] // THE FRUIT MUST BE UNIQUE! public string Name { get; set; } [Cfg] public List<Color> Colors {get; set;} }
如果我们想控制使用哪些颜色,我们可以像这样向颜色名称属性添加 domain="red,green,etc"
class Color : CfgNode { [Cfg(domain="red,yellow,green,blue,purple,orange")] public string Name {get; set;} }
加载配置
现在我们有了模型以及我们选择的 JSON 或 XML 配置,我们可以像这样将配置加载到模型中
// let's say the configuration is in the xml variable var cfg = new Cfg(); cfg.Load(xml);
检查配置
加载配置时,Cfg-NET 会检查错误和/或警告。
加载后,请务必使用 Errors()
和 Warnings()
方法检查模型是否存在任何问题
//LOAD CONFIGURATION var cfg = new Cfg(); cfg.Load(xml); /* CHECK FOR WARNINGS */ Assert.AreEqual(0, cfg.Warnings().Length); /* CHECK FOR ERRORS */ Assert.AreEqual(0, cfg.Errors().Length); /* EVERYTHING IS AWESOME!!! */
根据约定,错误意味着配置无效。警告是您应该处理的事情,但程序仍应正常运行。
应将错误和警告报告给最终用户,以便他们修复。以下是一些示例错误
删除必需的水果,然后……
fruit 必须在 cfg 中填充。
再添加一个苹果,然后……
在 fruit 中重复 name 值 apple。
添加粉色……
在 name 中发现无效值 pink。有效域为:red、yellow、green、purple、blue、orange。
如果 Cfg-NET 没有报告问题,则表示您的配置有效。您可以无忧无虑地遍历您的水果及其颜色
var cfg = new Cfg(); cfg.Load(xml); foreach (var fruit in cfg.Fruit) { foreach (var color in fruit.Colors) { /* use fruit.Name and color.Name... */ } }
您永远不必担心被 Cfg
装饰的列表为 null
,因为它们在加载配置时被初始化了。此外,如果您设置了默认值(例如 [Cfg(value="default")]
),则属性永远不会为 null
。
在 .NET Fiddle 上玩转苹果和香蕉。
自定义
Cfg
属性的可选属性提供了简单的验证。如果这不够,您还可以通过其他方式进行扩展
- 覆盖
PreValidate()
- 覆盖
Validate()
- 覆盖
PostValidate()
PreValidate()
如果您想在验证之前修改配置,请像这样覆盖 PreValidate()
protected override void PreValidate() { if (Provider == "Bad Words") { Provider = "Good Words. Ha!"; Warn("Please watch your language."); } }
Validate()
要执行涉及多个属性的验证,请像这样覆盖 Validate()
public class Connection : CfgNode { [Cfg(required = true, domain = "file,folder,other")] public string Provider { get; set; } [Cfg()] public string File { get; set; } [Cfg()] public string Folder { get; set; } /* CUSTOM VALIDATION */ protected override void Validate() { if (Provider == "file" && string.IsNullOrEmpty(File)) { Error("file provider needs file attribute."); } else if (Provider == "folder" && string.IsNullOrEmpty(Folder)) { Error("folder provider needs folder attribute."); } } }
当您覆盖 Validate
时,请使用 Error()
和 Warn()
方法添加问题。
PostValidate()
覆盖 PostValidate
可让您在验证后运行代码。您可以检查 Errors()
和/或 Warnings()
并进行进一步的准备。
protected override void PostValidate() { if (Errors().Length == 0) { /* make further preparations... */ } }
自定义
如果属性和方法不够,您可以在模型的构造函数中注入自定义器(例如:实现 ICustomizer
的类)。
序列化
将配置加载到代码后,您可以使用 Serialize()
将其序列化回字符串。
// load var cfg = new Cfg(); cfg.Load(xml); // modify cfg.Fruit.RemoveAll(f => f.Name == "apple"); cfg.Fruit.Add(new Fruit { Name = "plum", Colors = new List<Color> { new Color { Name = "purple" } } }); // serialize var result = cfg.Serialize();
这将产生一个结果
<cfg> <fruit> <add name="banana"> <colors> <add name="yellow" /> </colors> </add> <add name="plum"> <colors> <add name="purple" /> </colors> </add> </fruit> </cfg>
使用代码配置和检查
加载配置很棒。但是,有时您需要用代码编写配置,并且仍然能够检查它是否存在错误和/或警告。为此,只需按您喜欢的方式创建对象,然后运行 Check
方法。
var cfg = new Cfg { Fruit = new List<Fruit> { new Fruit { Name = "Apple", Colors = new List<Color> { new Color {Name = "red"}, new Color {Name = "aqua"} } } } }; // Instead of using Load(), use Check() cfg.Check(); // I put an error in there on purpose (hint: aqua is invalid) Assert.AreEqual(1, cfg.Errors().Length);
结论
因此,如果您需要为您的程序提供真正出色的配置,请尝试 Cfg-NET。我在几乎所有编写的程序中都使用它,并且对此非常满意。感谢您花时间阅读本文。我非常感谢您的点赞和反馈。