【问题标题】:How to deserialize JSON with cross reference?如何使用交叉引用反序列化 JSON?
【发布时间】:2015-04-19 17:39:59
【问题描述】:

我有这样的 JSON:

{
    "data": {
        "name": "xxx",
        "xxx": {
            "id": "1",
            "code": "12345",
            "description": "Hello"
        }
    }
}

我想将其反序列化为自定义 C# 类。 “data”是一个包含两个特定对的对象:第一对的值总是第二对的键(例如,{“name”:“yyy”,“yyy”:“some_object”})。我添加了两个类,但我不知道如何为“DataResponse”属性设置名称,因为它不是静态的:

public sealed class Data
{
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "xxx")]
    public DataResponse DataResponse { get; set; }
}

public sealed class DataResponse
{
    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [JsonProperty(PropertyName = "code")]
    public string Code { get; set; }

    [JsonProperty(PropertyName = "description")]
    public string Description { get; set; }
}

反序列化此 JSON 的主要代码:

Data data = JsonConvert.DeserializeObject<Data>(json);
// do some stuff with data...

【问题讨论】:

    标签: c# json json.net json-deserialization


    【解决方案1】:

    您可以使用简单的JsonConverter 来完成此操作。例如,如果我们让您的 Data 类成为支持任何对象值类型的泛型类,您会这样做:

    public sealed class Root<T>
    {
        public Data<T> data { get; set; }
    }
    
    [JsonConverter(typeof(GenericDataResponseConverter))]
    public sealed class Data<T>
    {
        public string Name { get; set; }
    
        public T DataResponse { get; set; }
    }
    
    class GenericDataResponseConverter : JsonConverter
    {
        Type GetDataResponseType(Type objectType)
        {
            return (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Data<>) ? objectType.GetGenericArguments()[0] : null);
        }
    
        public override bool CanConvert(Type objectType)
        {
            return GetDataResponseType(objectType) != null;
        }
    
        object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var data = ((Data<T>)existingValue) ?? new Data<T>();
            var obj = JObject.Load(reader);
            data.Name = (string)obj["name"];
            data.DataResponse = obj[data.Name].ToObject<T>(serializer);
            return data;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            var genericMethod = method.MakeGenericMethod(new[] { GetDataResponseType(objectType ) });
            return genericMethod.Invoke(this, new object[] { reader, objectType, existingValue, serializer });
        }
    
        void WriteJsonGeneric<T>(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var data = (Data<T>)value;
            var dict = new Dictionary<string, object> 
            {
                { "name", data.Name },
                { data.Name, data.DataResponse },
            };
            serializer.Serialize(writer, dict);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var method = GetType().GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            var genericMethod = method.MakeGenericMethod(new[] { GetDataResponseType(value.GetType()) });
            genericMethod.Invoke(this, new object[] { writer, value, serializer });
        }
    }
    

    然后,像这样使用它:

            var root = JsonConvert.DeserializeObject<Root<DataResponse>>(jsonString);
            Debug.WriteLine(JsonConvert.SerializeObject(root, Formatting.Indented));
    

    如果您不需要通用的DataResponse 类型,它会变得更加容易:

    public sealed class Root
    {
        public Data data { get; set; }
    }
    
    [JsonConverter(typeof(DataResponseConverter))]
    public sealed class Data
    {
        public string Name { get; set; }
    
        public DataResponse DataResponse { get; set; }
    }
    
    class DataResponseConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Data);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var data = ((Data)existingValue) ?? new Data();
            var obj = JObject.Load(reader);
            data.Name = (string)obj["name"];
            data.DataResponse = obj[data.Name].ToObject<DataResponse>(serializer);
            return data;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var data = (Data)value;
            var dict = new Dictionary<string, object> 
            {
                { "name", data.Name },
                { data.Name, data.DataResponse },
            };
            serializer.Serialize(writer, dict);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 1970-01-01
      • 2017-09-14
      相关资源
      最近更新 更多