0

我有一个这样的用例,并找到一种将 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;
        }
    }

再次开始读取第一个 json token导致出现错误serializer.Deserialize,无法创建 A 或 B 的实例。此时如何继续解析以获取 A 和 B 的实例?想想case类A和B还是有很多属性的,所以为它们写自定义的json转换器并不是一个好的解决方案。

谁能帮我一个解决方案和可视化代码将上面的 json 字符串反序列化为 Results 对象?


解决方案

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

为了解决这个问题,我添加了这行代码以确保 Result 对象在 json 阅读器转到对象末尾时立即返回。该对象将被添加到列表中,并且下一个 Search 对象将被反序列化...

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

0 回答 0