【问题标题】:Deserialize a complex json object c#反序列化一个复杂的json对象c#
【发布时间】:2020-01-15 17:11:00
【问题描述】:

我有这样一个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"
            }
        ]
    ]

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

【问题讨论】:

  • 我假设,在您的第二个 sn-p(以 "value" 开头)中,您根本没有提供前一个 sn-p 的页眉/页脚 - ala { "status": "Success",} 然后在结束括号}?只是想在任何问题之前弄清楚你的 JSON 的结构。
  • 您是否完全控制了这个 JSON?目前的结构非常不幸。您可能需要一个自定义序列化程序,或者通过JObject 或类似方式进行。如果您可以重新设计 JSON,那将使生活变得更加简单。
  • @JonSkeet 这不是我的对象,我是根据文档得到的
  • 我不太清楚你的意思,但我们应该明白你绝对不能改变 JSON 结构吗?
  • @JonSkeet 不,我不能影响她。

标签: c# deserialization json-deserialization


【解决方案1】:

我可能会使用 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; }
}

【讨论】:

    【解决方案2】:

    我能够用

    生成转换器

    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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      • 2021-09-23
      相关资源
      最近更新 更多