JSON将一个数据反序列化为数组,并将一个数据反序列化为json对象

pdsfdshx  于 2023-05-19  发布在  其他
关注(0)|答案(1)|浏览(209)

我有下面的json,我试图反序列化它。棘手的部分是,在一个节点中,名称图像在一些数据中,它是作为数组来的,在一些它是作为JSON对象来的。所以我可以一次反序列化两个。
这是JSON格式。

{
  "variants": [
    {
      "name": "test1",
      "description": "test1",
      "images": []
    },
    {
      "name": "test2",
      "description": "test2",
      "images": {
        "WHITE": [
          {
            "id": "ttest",
            "product_id": "ttest"
          }
        ]
      }
    }
  ]
}

现在,正如你在这里看到的图像,在一个我们有一个数组,在一个我们有json对象。
我试过下面。

public List<Variant> variants { get; set; }

public class Variant
    {
        public string name { get; set;}
        public string description { get; set;}
        public List<Image> images { get; set; }
    }

public class Image
    {
        public List<White> White { get; set; }
    }

public class White
    {
        public string id { get; set;}
        public string product_id { get; set;}
    }

然后在下面一行进行反序列化:
var items = JsonConvert.DeserializeObject<TestClass>(content);

83qze16e

83qze16e1#

images的值似乎是:

  • 一个对象,对应于任意颜色的图像数据列表的字典,这里是"WHITE"
  • 当没有颜色值时,空数组

由于images的值有时是一个数组,有时是一个对象,因此需要使用适当的custom JsonConverter<T>将其反序列化。
具体来说,定义以下数据模型:

public class TestClass
{
    public List<Variant> variants { get; set; } = new ();
}

public class Variant
{
    public string name { get; set; }
    public string description { get; set; }
    
    [JsonConverter(typeof(JsonSingleOrEmptyArrayConverter<Dictionary<string, List<Image>>>))]
    public Dictionary<string, List<Image>> images { get; set; } = new ();
}

public class Image
{
    public string id { get; set; }
    public string product_id { get; set; }
}

其中JsonSingleOrEmptyArrayConverter<T>this answer逐字复制到 Cannot Deserialize the Current JSON Object (Empty Array)

public class JsonSingleOrEmptyArrayConverter<T> : JsonConverter where T : class
{
    // Copied from this answer https://stackoverflow.com/a/53219877
    // To https://stackoverflow.com/questions/53219668/cannot-deserialize-the-current-json-object-empty-array
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var contract = serializer.ContractResolver.ResolveContract(objectType);
        // Allow for dictionary contracts as well as objects contracts, since both are represented by 
        // an unordered set of name/value pairs that begins with { (left brace) and ends with } (right brace).
        if (!(contract is Newtonsoft.Json.Serialization.JsonObjectContract 
              || contract is Newtonsoft.Json.Serialization.JsonDictionaryContract))
        {
            throw new JsonSerializationException(string.Format("Unsupported objectType {0} at {1}.", objectType, reader.Path));
        }

        switch (reader.SkipComments().TokenType)
        {
            case JsonToken.StartArray:
                {
                    int count = 0;
                    while (reader.Read())
                    {
                        switch (reader.TokenType)
                        {
                            case JsonToken.Comment:
                                break;
                            case JsonToken.EndArray:
                                // You might want to allocate an empty object here if existingValue is null
                                // If so, do
                                // return existingValue ?? contract.DefaultCreator();
                                return existingValue;
                            default:
                                {
                                    count++;
                                    if (count > 1)
                                        throw new JsonSerializationException(string.Format("Too many objects at path {0}.", reader.Path));
                                    existingValue = existingValue ?? contract.DefaultCreator();
                                    serializer.Populate(reader, existingValue);
                                }
                                break;
                        }
                    }
                    // Should not come here.
                    throw new JsonSerializationException(string.Format("Unclosed array at path {0}.", reader.Path));
                }

            case JsonToken.Null:
                return null;

            case JsonToken.StartObject:
                existingValue = existingValue ?? contract.DefaultCreator();
                serializer.Populate(reader, existingValue);
                return existingValue;

            default:
                throw new InvalidOperationException("Unexpected token type " + reader.TokenType.ToString());
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static partial class JsonExtensions
{
    public static JsonReader SkipComments(this JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment && reader.Read())
            ;
        return reader;
    }
}

现在你可以通过简单地执行以下操作来反序列化你的JSON:

var root = JsonConvert.DeserializeObject<TestClass>(json);

演示小提琴here

相关问题