Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于字典键的JSON推断类类型_C#_Json_Dictionary_Serialization_Json.net - Fatal编程技术网

C# 基于字典键的JSON推断类类型

C# 基于字典键的JSON推断类类型,c#,json,dictionary,serialization,json.net,C#,Json,Dictionary,Serialization,Json.net,我想反序列化词典AbstractDataObject是SomeClass1和SomeClass2继承自的抽象类。字典的键值(字符串)是类的名称: { "StoredData": { "SomeClass1": { "Foo": "Test" }, "SomeClass2": { "Bar": 123 } } } 这些类如下所示(简化): 公共类数据 { 公共字典存储数据{get;set;} } 公共抽象类AbstractDataO

我想反序列化
词典
AbstractDataObject
SomeClass1
SomeClass2
继承自的抽象类。字典的键值(字符串)是类的名称:

{
  "StoredData": {
    "SomeClass1": {
      "Foo": "Test"
    },
    "SomeClass2": {
      "Bar": 123
    }
  }
}
这些类如下所示(简化):

公共类数据
{
公共字典存储数据{get;set;}
}
公共抽象类AbstractDataObject
{
}
公共类SomeClass1:AbstractDataObject
{
公共字符串Foo{get;set;}
}
公共类SomeClass2:AbstractDataObject
{
公共整型条{get;set;}
}

如何让Json.NET根据字典键推断类类型?我环顾四周,但不确定从何处开始实现此功能

您可以制作一个自定义的
JsonConverter
来处理此问题:

public class CustomDictionaryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<string, AbstractDataObject>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var dict = new Dictionary<string, AbstractDataObject>();
        JObject jo = JObject.Load(reader);
        foreach (JProperty prop in jo.Properties())
        {
            switch (prop.Name)
            {
                case "SomeClass1":
                    dict.Add("SomeClass1", prop.Value.ToObject<SomeClass1>(serializer));
                    break;

                case "SomeClass2":
                    dict.Add("SomeClass2", prop.Value.ToObject<SomeClass2>(serializer));
                    break;
            }
        }
        return dict;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
公共类CustomDictionaryConverter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(字典);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
var dict=新字典();
JObject jo=JObject.Load(读卡器);
foreach(jo.Properties()中的JProperty属性)
{
开关(道具名称)
{
案例“SomeClass1”:
dict.Add(“SomeClass1”,prop.Value.ToObject(序列化程序));
打破
案例“SomeClass2”:
dict.Add(“SomeClass2”,prop.Value.ToObject(序列化程序));
打破
}
}
返回命令;
}
公共覆盖布尔可写
{
获取{return false;}
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
}
然后像这样使用它:

Data data = JsonConvert.DeserializeObject<Data>(json, new CustomDictionaryConverter());
Data Data=JsonConvert.DeserializeObject(json,新的CustomDictionaryConverter());

Fiddle:

使用类型名是危险的,因为它破坏了序列化的典型目的,即允许完全解耦的客户端/服务器。有没有一种方法可以设计成显式契约?@SilasReinagel显式契约是什么意思?例如,对于特定的远程调用,在客户端代码中使用具体的数据对象。@SilasReinagel哦,这需要完全重写我当前的代码库:(还有什么方法可以实现我想要的功能吗?我不相信Json.NET中包含了这些功能。在反序列化之前,您必须自己创建一个层来确定类型。这不是很难做到,但可能会在项目的后续阶段给您带来一些麻烦。
Data data = JsonConvert.DeserializeObject<Data>(json, new CustomDictionaryConverter());