适用版本:NX6以上
在应用程序的配置文件方面,长期以来我们研发团队内部都是根据各个项目的情况进行制定,也有的时候因为客户方并没有要求,可能是按照开发人员自己的经验、习惯和偏好制定,并没有统一的标准、格式以及代码只对应的接口方便其他人调用。本技巧则对目前存在的一些配置文件方法进行总结和比较。
JSON格式
JSON(JavaScript ObjectNotation, JS 对象简谱)是一种轻量级的数据交换格式。它基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
优点和缺点
与XML一样,JSON也是一种文本格式,因此也可以轻松地使用文本编辑工具进行手动编辑。JSON和XML都是树结构,但和XML由元素和属性构成不同,JSON由对象、数组、字符串、数值、布尔值和空值组成。JSON的组成和面向对象编程语言中的对象类似,甚至在Javascript中可以直接使用JSON的语法定义一个对象。对于表示对象中的一个简单的值属性,在XML中可以用元素或属性的方式表示,这时就存在一个选择的问题。但在JSON中表示的方式是唯一的,而且和它原来的结构非常相似。对于简单的值,JSON提供不同的类型,特别是可以直接获取数值类型,而XML则需要将字符串再次解析为数值。JSON对于数组的支持也是相对XML的一个很大的优点,虽然XML也可以通过树结构表达集合,但因为不是语法直接支持会增加很多的文本量,读起来也更困难。
XML通常认为是一种比较“重型”的格式,大量的冗余提供了更强大的功能。相比下轻型的JSON也可以实现XML的大部分功能,而实现同样功能的情况下因为文本较小因此数度更快。可读性方面,XML和JSON都需要人员对语法有一定的知识,相比下JSON较短读起来也更简洁明了。
JSON中使用了更多的括号和特殊符号,这对开发人员来说较为自然,但是对于一般人员想手动对JSON文本进行编辑的时候可能会由于忘记了符号而造成语法错误,无法解析的情况。JSON标准中没有对于注释的支持也是一个问题,虽然在一些更新版本的标准中提供了注释的规范。
作为配置文件格式
JSON的基本结构其实是一种”键——值“结构,因此同样非常适合作为简单配置文件的格式:
另外JSON对数组的支持也方便了多个值的配置项:
.NET中要到5.0后才原生支持JSON文件的读写和序列化,而我们NX二次开发一般都达不到这么高的.NET版本。但是.NET中可以使用Newtonsoft.Json,它是.NET中使用最广泛的第三方库,开源而且完全免费,具有强大、易用的JSON读写和序列化功能。
为了将JSON作为配置文件,我们可以将配置项设置为JSON中的键和值,如上示例,然后在C#编写一个对应的类:
从JSON文件中使用Newtonsoft.Json反序列化,获取Settings的实例并在程序中使用:
通用JSON配置文件基类
因为使用JSON配置文件类的功能都类似,我们可以设置一个配置基类,让程序的其他配置类都由这个基类派生,并在基类中添加读写方法和默认配置静态实例。静态实例可以让下游程序直接调用配置值而不需要先调用读取方法:
///
/// JSON配置基类 /// /// 子类的类型 public abstract class JsonConfigBaseT> where T : JsonConfigBaseT>, new() { private static T _default;
///
/// 从默认文件中获取的值 /// /// /// 从不同的源获取值, 优先级从低到高为: 类定义的默认值->资源中JSON定义的值->程序目录下JSON定义的值 /// 高优先级将覆盖低优先级 /// JSON文件的命名规则为: [程序名].[类名].json /// public static T Default { get { if (_default == null) { ReloadDefault(); } return _default; } }
///
/// 重新加载默认值 /// public static void ReloadDefault() { T obj = new T(); Type type = typeof(T); Assembly assem = type.Assembly; string jsonName = $“{assem.GetName().Name}.{type.Name}.json”; string[] names = assem.GetManifestResourceNames(); string resource = names.FirstOrDefault(q => q.Contains(jsonName)); if (resource != null) { using (StreamReader sr = new StreamReader(assem.GetManifestResourceStream(resource))) { string jsonStr = sr.ReadToEnd(); JsonConvert.PopulateObject(jsonStr, obj); } } string dir = Path.GetDirectoryName(assem.Location); string jsonPath = Path.Combine(dir, jsonName); if (File.Exists(jsonPath)) { string jsonStr = File.ReadAllText(jsonPath); JsonConvert.PopulateObject(jsonStr, obj); } _default = obj; }
///
/// 将JSON输出到文件 /// /// public void WriteToFile(string path) { string jsonStr = JsonConvert.SerializeObject(this, Formatting.Indented); File.WriteAllText(path, jsonStr); }
///
/// 从JSON中获取值并覆盖当前值 /// /// public void LoadFromFile(string path) { string jsonStr = File.ReadAllText(path); JsonConvert.PopulateObject(jsonStr, this); } }
|
由此,第二节的例子可以简化为(需要将JSON文件命名为程序名.Setting.json,并放到程序同一目录下):
使用JSON作为配置文件格式,并通过JSON文件基类创建新的配置类,可以规范地创建高效的配置文件模式,虽然在工具上不如XML有VS的内置工具和.NET的原生支持,但是由于JSON的优点也有原来越多的软件使用JSON作为配置文件格式。