繁体   English   中英

反序列化一个复杂的 json 对象 c#

[英]Deserialize a complex json object c#

我有这样一个json对象:

{
        "status": "Success",
        "value": [
            [
                "2019-10-21T11:48:00Z",
                "010719/360",
                "hodler@hodler.hodler",
                {
                    "role": "hodler",
                    "company": "Proximus",
                    "first_name": "Ivan",
                    "last_name": "Holms",
                    "modification_date": "2019-10-21 10:33:39"
                }
            ]
        ]
    }

在此之前,我总是使用var obj = JsonConvert.DeserializeObject<MyDistClass>(json); 但我不明白如何描述这个实体:

"value": [
        [
            "2019-10-21T11:48:00Z",
            "010719/360",
            "holder@holder.holder",
            {
                "role": "holder",
                "company": "Proximus",
                "first_name": "Marc",
                "last_name": "Neukirch",
                "modification_date": "2019-10-21T10:33:39"
            }
        ]
    ]

我尝试了所有我知道的类,甚至尝试替换元组,但没有结果。 请帮帮我。

我可能会使用 Json.NET 将 JSON 解析为JObject ,然后从中提取相关值 - 尽可能使用JToken.ToObject<>

下面是一些看似有效的示例代码 - 但需要大量验证和一般整理。 更重要的是展示这个想法而不是其他任何事情:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        string json = File.ReadAllText("test.json");
        Result result = Result.FromJson(json);
        Console.WriteLine(result.Status);
        Console.WriteLine(result.Values.Count);
        Console.WriteLine(result.Values[0].User.FirstName);
    }
}

public sealed class Result
{
    public string Status { get; }
    public IReadOnlyList<ResultValue> Values { get; }

    private Result(string status, IReadOnlyList<ResultValue> values) =>
        (Status, Values) = (status, values);

    public static Result FromJson(string json)
    {
        JObject parsed = JObject.Parse(json);
        string status = (string) parsed["status"];
        JArray array = (JArray) parsed["value"];
        var values = array.Select(ResultValue.FromJToken).ToList().AsReadOnly();
        return new Result(status, values);
    }
}

public sealed class ResultValue
{
    public DateTime Timestamp { get; }
    public string Id { get; }
    public string Email { get; }
    public User User { get; }

    private ResultValue(DateTime timestamp, string id, string email, User user) =>
        (Timestamp, Id, Email, User) = (timestamp, id, email, user);

    internal static ResultValue FromJToken(JToken token)
    {
        JArray array = (JArray) token;
        DateTime timestamp = (DateTime) array[0];
        string id = (string) array[1];
        string email = (string) array[2];
        User user = array[3].ToObject<User>();
        return new ResultValue(timestamp, id, email, user);
    }
}

// TODO: Make this immutable, or everything else immutable
public sealed class User
{
    [JsonProperty("role")]
    public string Role { get; set; }
    [JsonProperty("company")]
    public string Company { get; set; }
    [JsonProperty("first_name")]
    public string FirstName { get; set; }
    [JsonProperty("last_name")]
    public string LastName { get; set; }
    [JsonProperty("modification_date")]
    public DateTime ModificationDate { get; set; }
}

我能够生成一个转换器

https://app.quicktype.io/?l=csharp

似乎工作得很好。
这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace QuickType
{
    public partial class Request
    {
        [JsonProperty("status")]
        public string Status { get; set; }

        [JsonProperty("value")]
        public ValueElement[][] Value { get; set; }
    }

    public partial class ValueClass
    {
        [JsonProperty("role")]
        public string Role { get; set; }

        [JsonProperty("company")]
        public string Company { get; set; }

        [JsonProperty("first_name")]
        public string FirstName { get; set; }

        [JsonProperty("last_name")]
        public string LastName { get; set; }

        [JsonProperty("modification_date")]
        public DateTimeOffset ModificationDate { get; set; }
    }

    public partial struct ValueElement
    {
        public string String;
        public ValueClass ValueClass;

        public static implicit operator ValueElement(string String) => new ValueElement { String = String };
        public static implicit operator ValueElement(ValueClass ValueClass) => new ValueElement { ValueClass = ValueClass };
    }

    internal static class Converter2
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                ValueElementConverter.Singleton,
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }

    internal class ValueElementConverter : JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(ValueElement) || t == typeof(ValueElement?);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            switch (reader.TokenType)
            {
                case JsonToken.String:
                case JsonToken.Date:
                    var stringValue = serializer.Deserialize<string>(reader);
                    return new ValueElement { String = stringValue };
                case JsonToken.StartObject:
                    var objectValue = serializer.Deserialize<ValueClass>(reader);
                    return new ValueElement { ValueClass = objectValue };
            }
            throw new Exception("Cannot unmarshal type ValueElement");
        }

        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
        {
            var value = (ValueElement)untypedValue;
            if (value.String != null)
            {
                serializer.Serialize(writer, value.String);
                return;
            }
            if (value.ValueClass != null)
            {
                serializer.Serialize(writer, value.ValueClass);
                return;
            }
            throw new Exception("Cannot marshal type ValueElement");
        }

        public static readonly ValueElementConverter Singleton = new ValueElementConverter();
    }
}

像这样反序列化:

var myObject = JsonConvert.DeserializeObject<Request>(json, Converter2.Settings);

暂无
暂无

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

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