YamlDotNet を使用して単純な構成ファイルを解析しています (深いネストなどはありません)。デシリアライザーは、重複するフィールドを含む文字列を解析し、以前の値を上書きします。例えば、
foo: bar
foo: baz
と同等と見なされます
foo: baz
私のアプリケーションでは、そのような重複によって例外がスローされることを望みます。これは可能ですか?
YamlDotNet を使用して単純な構成ファイルを解析しています (深いネストなどはありません)。デシリアライザーは、重複するフィールドを含む文字列を解析し、以前の値を上書きします。例えば、
foo: bar
foo: baz
と同等と見なされます
foo: baz
私のアプリケーションでは、そのような重複によって例外がスローされることを望みます。これは可能ですか?
このUniqueKeysDictionary
例は私にはうまくいきませんでした.2番目の例から、正確に検証する方法が明確ではありませんでした. しかし、重複が許可されておらず、ファイルを2回ロードしても問題ない場合は、はるかに簡単な方法を見つけました。
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;
}
}
リンターを含む解決策がありますが、YamlDotNet で例外がスローされることはないため、それがあなたに関連するかどうかはわかりません。の実装を置き換えることを避けることができるので、とにかく投稿します
GenericDictionaryNodeDeserializer
。
これはyamllintコマンドライン ツールです。
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)
デフォルトのノード デシリアライザーは、インデクサーを使用して値を割り当てます。目的の動作を実現する 1 つの方法は、次のように値の重複を許可しない型に逆シリアル化することです。
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); }
}
}
このソリューションの重大な問題の 1 つは、インデクサーのコントラクトに違反していることです。インデクサーの動作は、値を上書きする必要があります。
もう 1 つのアプローチは、 の実装を、インデクサーの代わりにメソッド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);