最近同じような問題があったので、帽子をリングに投げ込むと思いました。これが私が逆シリアル化したかったJSONの例です:
{
"agencyId": "agency1",
"overrides": {
"assumption.discount.rates": "value: 0.07",
".plan": {
"plan1": {
"assumption.payroll.growth": "value: 0.03",
"provision.eeContrib.rate": "value: 0.35"
},
"plan2": {
".classAndTier": {
"misc:tier1": {
"provision.eeContrib.rate": "value: 0.4"
},
"misc:tier2": {
"provision.eeContrib.rate": "value: 0.375"
}
}
}
}
}
}
これは、オーバーライドがさまざまなレベルで適用され、ツリーの下に継承されるシステム用です。いずれにせよ、私が望んでいたデータモデルは、これらの特別な継承ルールも提供されたプロパティバッグを持つことができるものでした。
私が最終的に得たのは次のとおりです。
public class TestDataModel
{
public string AgencyId;
public int Years;
public PropertyBagModel Overrides;
}
public class ParticipantFilterModel
{
public string[] ClassAndTier;
public string[] BargainingUnit;
public string[] Department;
}
public class PropertyBagModel
{
[JsonExtensionData]
private readonly Dictionary<string, JToken> _extensionData = new Dictionary<string, JToken>();
[JsonIgnore]
public readonly Dictionary<string, string> Values = new Dictionary<string, string>();
[JsonProperty(".plan", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByPlan;
[JsonProperty(".classAndTier", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByClassAndTier;
[JsonProperty(".bargainingUnit", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByBarginingUnit;
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
foreach (var kvp in Values)
_extensionData.Add(kvp.Key, kvp.Value);
}
[OnSerialized]
private void OnSerialized(StreamingContext context)
{
_extensionData.Clear();
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
Values.Clear();
foreach (var kvp in _extensionData.Where(x => x.Value.Type == JTokenType.String))
Values.Add(kvp.Key, kvp.Value.Value<string>());
_extensionData.Clear();
}
}
基本的な考え方は次のとおりです。
- JSON.NETによる逆シリアル化のPropertyBagModelには、ByPlan、ByClassAndTierなどのフィールドが入力されており、private_extensionDataフィールドも入力されています。
- 次に、JSON.NETはプライベートOnDeserialized()メソッドを呼び出し、データを_extensionDataからValuesに適切に移動します(または、それ以外の場合はフロアにドロップします-おそらく、知りたい場合はこれをログに記録できます)。次に、_extensionDataから余分なガンクを削除して、メモリを消費しないようにします。
- シリアル化の際、OnSerializingメソッドは、データを_extensionDataに移動して保存する呼び出しを取得します。
- シリアル化が完了すると、OnSerializedが呼び出され、_extensionDataから余分なものが削除されます。
必要に応じて_extensionDataディクショナリをさらに削除して再作成することもできますが、これらのオブジェクトを大量に使用していないため、実際の値は表示されませんでした。これを行うには、OnSerializingで作成し、OnSerializedで削除します。OnDeserializingでは、クリアする代わりに、それを解放することができます。