自定义Json转换器

时间:2013-10-08 11:42:50

标签: c# json serialization

我有一个这样的用例,并找到一种方法将json字符串反序列化为C#对象

Json数据如下detail属性取决于type属性

    {
      data: [
        {
           type: "A",
           detail: {
              property_a: "plan A"
           }
        },
        {
           type: "B",
           detail: {
              property_b: "plan B"
           }
        },
        {
           type: "A",
           detail: {
              property_a: "new"
           }
        }
      ]
    }

C#模型

    public class Results
    {
       [JsonProperty(PropertyName = "data")]
       public List<Result> Data { get; set; }
    }

    public class Result
    {
       [JsonProperty(PropertyName = "type"]
       public string Type { get; set; }

       [JsonProperty(PropertyName = "detail"]
       public Detail Detail { get; set; }
    }

    public class Detail
    {
    }

    public class A: Detail
    {
       [JsonProperty(PropertyName = "property_a")]
       public string PropertyA { get; set; }
    }

    public class B: Detail
    {
       [JsonProperty(PropertyName = "property_b")]
       public string PropertyB { get; set; }
    }

第一次尝试将json字符串反序列化为C#

    var results = JsonConvert.DeserializeObject<Results>(jsonString);
    // results.Data will contains 3 instances of Detail class, not A or B
    // therefore, I cannot cast each of them to A or B for usage later.

然后,我尝试为Result类创建CustomCreationConverter

    public class JsonConverter: CustomCreationConverter<Result>
    {
        public override SearchResult Create(Type objectType)
        {
            return new Result();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var result = new Result();

            // loop through JSON string
            while (reader.Read())
            {
                // return because it is now the end of object
                if (reader.TokenType == JsonToken.EndObject) 
                    return result;

                if (reader.TokenType != JsonToken.PropertyName) 
                    continue;

                var propertyName = reader.Value.ToString();

                if (!reader.Read()) 
                    return result;

                if ("type".Equals(propertyName))
                {
                    result.Type = reader.Value != null ? reader.Value.ToString() : null;
                }
                else if ("detail".Equals(propertyName))
                {
                    // parse to instantiate A or B
                    switch (result.Type)
                    {
                        case "A":
                           result.Detail = serializer.Deserialize<A>(reader);
                           break;
                        case "B":
                           result.Detail = serializer.Deserialize<B>(reader);
                           break;
                        default:
                           break;
                    }
                 }
            }

            return result;
        }
    }

发生错误是因为serializer.Deserialize再次开始读取第一个json令牌而无法创建A或B的实例。如何在此时继续解析以获取A和B的实例?想想案例类A和B仍然有很多属性,所以为它们编写自定义json转换器不是一个好的解决方案。

任何人都可以帮我解决方案和可视化代码,将上面的json字符串反序列化为Results对象吗?


我已经下载了Newtonsoft.Json的源代码进行调试,并找到了问题的根本原因。我误解了serializer.Deserialize方法的逻辑。它有助于读取Json令牌并将对象构建为默认行为,因此没有问题。

为了解决这个问题,我添加了这行代码,以确保一旦json reader转到对象的末尾就返回Result对象。此对象将添加到列表中,下一个搜索对象将被反序列化...

    // return because it is now the end of object
    if (reader.TokenType == JsonToken.EndObject) 
        return result;

0 个答案:

没有答案