繁体   English   中英

如何反序列化具有不同类型和元素数量的元素的JSON数组?

[英]How to deserialize a JSON array of elements with different types and varying number of elements?

我正在处理一个JSON数组,其中每个元素具有不同的类型,由type属性指示。 可以有多个相同类型的元素,并且元素的数量事先未知。 那是:

[
  {
    'abc': '0',
    'type': 'a'
  },
  {
    'cde': '10',
    'type: 'b'
  },
  {
    'abc': '20'
    'type': 'a'
  }
]

我需要将这样的数组反序列化为List<A>List<B>

我查看了Json.NET文档,但不确定将什么用于此任务是一个好的策略或功能。 任何指针将不胜感激。

假设您的类型都是已知的,则可以将所有元素反序列化为JObject并使用linq将初始数组分成多个列表。

您可以声明dbc建议的抽象基本类型,而不是使用List<JObject> ,然后实现自定义JsonConverter。

无论哪种情况,如果您想要每种子类型的单独列表,则需要迭代将超类型转换为子类型的初始数组。

定义您的类型:

class A
{
    public int abc { get; set; }
}

class B
{
    public int cde { get; set; }
}

然后反序列化您的基本数组,并使用linq拆分为两个单独的列表。

string json = @"[
    {
    'abc': '0',
    'type': 'a'
    },
    {
    'cde': '10',
    'type': 'b'
    },
    {
    'abc': '20',
    'type': 'a'
    }
]";

List<JObject> objs = JsonConvert.DeserializeObject<List<JObject>>(json);

List<A> objectsA = objs.Where(d => d["type"].ToString() == "a").Select(d => d.ToObject<A>()).ToList();
List<B> objectsB = objs.Where(d => d["type"].ToString() == "b").Select(d => d.ToObject<B>()).ToList();

重新阐述此处此处给出的答案,并使用dbc所述的基类,可以获得所需的结果。

首先,定义类型:

class BaseClass
{
    [JsonProperty("type")]
    public string EntityType
    { get; set; }
}

class A : BaseClass
{
    public int abc { get; set; }
}

class B : BaseClass
{
    public int cde { get; set; }
}

然后,定义自定义创建转换器:

class BaseClassConverter : JsonCreationConverter<BaseClass>
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Implement this if you need to serialize the object too
        throw new NotImplementedException();
    }

    protected override BaseClass Create(Type objectType, JObject jObject)
    {
        if (jObject["type"].Value<string>() == "a")
        {
            return new A();
        }
        else
        {
            return new B();
        }
    }
}

public abstract class JsonCreationConverter<T> : JsonConverter
{
    /// <summary>
    /// Create an instance of objectType, based properties in the JSON object
    /// </summary>
    /// <param name="objectType">type of object expected</param>
    /// <param name="jObject">
    /// contents of JSON object that will be deserialized
    /// </param>
    /// <returns></returns>
    protected abstract T Create(Type objectType, JObject jObject);

    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)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}

最后,您反序列化json并获取所需的列表:

string json = @"[
        {
        'abc': '0',
        'type': 'a'
        },
        {
        'cde': '10',
        'type': 'b'
        },
        {
        'abc': '20',
        'type': 'a'
        }
    ]";


    List<BaseClass> objects = JsonConvert.DeserializeObject<List<BaseClass>>(json, new BaseClassConverter());
    List<A> aObjects = objects.Where(t => t.GetType() == typeof(A)).Select(o => (A)o).ToList();
    List<B> bObjects = objects.Where(t => t.GetType() == typeof(B)).Select(o => (B)o).ToList();

当且仅当type属性是您类型的完全限定名称时,才可以在定制创建转换器中使用此名称:

protected override BaseClass Create(Type objectType, JObject jObject)
{
     string type = jObject["type"].Value<string>();
     return (BaseClass)Activator.CreateInstance(Type.GetType(type));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM