我正在使用 YamlDotNet 来解析简单的配置文件(没有深度嵌套等)。反序列化器将解析包含重复字段的字符串,覆盖之前的值。例如,
foo: bar
foo: baz
被认为等同于
foo: baz
对于我的应用程序,我希望这样的重复会导致抛出异常。这可能吗?
我正在使用 YamlDotNet 来解析简单的配置文件(没有深度嵌套等)。反序列化器将解析包含重复字段的字符串,覆盖之前的值。例如,
foo: bar
foo: baz
被认为等同于
foo: baz
对于我的应用程序,我希望这样的重复会导致抛出异常。这可能吗?
该UniqueKeysDictionary
示例对我不起作用,并且从第二个示例中不清楚如何准确验证。但是如果不允许任何重复并且两次加载文件是可以接受的,我发现了更简单的方法:
private T DeserializeAndValidate<T>(StreamReader reader)
{
var yaml = new YamlStream();
yaml.Load(reader); // throws if duplicates are found
reader.BaseStream.Seek(0, SeekOrigin.Begin);
using (var reader2 = new StreamReader(reader.BaseStream))
{
var deserializer = new Deserializer();
var data = deserializer.Deserialize<T>(reader2);
return data;
}
}
默认节点反序列化器使用索引器来分配值。实现所需行为的一种方法是反序列化为不允许重复值的类型,例如:
public class UniqueKeysDictionary<TKey, TValue>
: Dictionary<TKey, TValue>
, IDictionary<TKey, TValue>
{
TValue IDictionary<TKey, TValue>.this[TKey key]
{
get { return base[key]; }
set { base.Add(key, value); }
}
}
该解决方案的一个重要问题是它违反了indexer 的约定,其行为应该是覆盖该值。
另一种方法是将 的实现替换为GenericDictionaryNodeDeserializer
使用该Add()
方法而不是索引器的实现。这是另一个示例的相关部分,展示了如何替换节点解串器:
var deserializer = new Deserializer();
var objectDeserializer = deserializer.NodeDeserializers
.Select((d, i) => new {
Deserializer = d as ObjectNodeDeserializer,
Index = i
})
.First(d => d.Deserializer != null);
deserializer.NodeDeserializers[objectDeserializer.Index] =
new ValidatingNodeDeserializer(objectDeserializer.Deserializer);
有一个涉及 linter 的解决方案,但我不确定它是否与您相关,因为它不会导致在 YamlDotNet 中引发异常。无论如何我都会发布它,因为它可以避免替换
GenericDictionaryNodeDeserializer
.
这是yamlint命令行工具:
sudo pip install yamllint
具体来说,它有一个key-duplicates
检测重复键的规则:
$ cat test.yml
foo: bar
foo: baz
$ yamllint test.yml
test.yml
2:1 error duplication of key "foo" in mapping (key-duplicates)