最近同じような問題があったので、帽子をリングに投げ込むと思いました。これが私が逆シリアル化したかった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では、クリアする代わりに、それを解放することができます。