如何使用JSON.net处理同一属性的单个项目和数组

前端之家收集整理的这篇文章主要介绍了如何使用JSON.net处理同一属性的单个项目和数组前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图修复我的SendGridPlus库来处理SendGrid事件,但我有一些麻烦的API中类别的不一致的处理。

在下面的示例负载取自SendGrid API reference,你会注意到每个项目的category属性可以是单个字符串或字符串数​​组。

[
  {
    "email": "john.doe@sendgrid.com","timestamp": 1337966815,"category": [
      "newuser","transactional"
    ],"event": "open"
  },{
    "email": "jane.doe@sendgrid.com","category": "olduser","event": "open"
  }
]

看来我的选择使JSON.NET像这样是固定字符串之前,或配置JSON.NET接受不正确的数据。我宁愿不做任何字符串解析,如果我可以逃脱它。

有没有任何其他方式,我可以使用Json.Net处理这个?

处理这种情况的最好方法是使用自定义 JsonConverter

在我们进入转换器之前,我们需要定义一个类来反序列化数据。对于可以在单个项目和数组之间变化的Categories属性,将其定义为List< string>并使用[JsonConverter]属性标记它,以便JSON.Net将知道使用该属性自定义转换器。我还建议使用[JsonProperty]属性,以便可以给成员属性赋予有意义的名称,而与JSON中定义的名称无关。

class Item
{
    [JsonProperty("email")]
    public string Email { get; set; }

    [JsonProperty("timestamp")]
    public int Timestamp { get; set; }

    [JsonProperty("event")]
    public string Event { get; set; }

    [JsonProperty("category")]
    [JsonConverter(typeof(SingleOrArrayConverter<string>))]
    public List<string> Categories { get; set; }
}

这里是如何实现转换器。注意我已经使转换器通用,以便它可以用于字符串或其他类型的对象所需要的。

class SingleOrArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<T>));
    }

    public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }
        return new List<T> { token.ToObject<T>() };
    }

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

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

这里是一个简短的程序演示转换器与您的示例数据:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        [
          {
            ""email"": ""john.doe@sendgrid.com"",""timestamp"": 1337966815,""category"": [
              ""newuser"",""transactional""
            ],""event"": ""open""
          },{
            ""email"": ""jane.doe@sendgrid.com"",""category"": ""olduser"",""event"": ""open""
          }
        ]";

        List<Item> list = JsonConvert.DeserializeObject<List<Item>>(json);

        foreach (Item obj in list)
        {
            Console.WriteLine("email: " + obj.Email);
            Console.WriteLine("timestamp: " + obj.Timestamp);
            Console.WriteLine("event: " + obj.Event);
            Console.WriteLine("categories: " + string.Join(",",obj.Categories));
            Console.WriteLine();
        }
    }
}

最后,这里是上面的输出

email: john.doe@sendgrid.com
timestamp: 1337966815
event: open
categories: newuser,transactional

email: jane.doe@sendgrid.com
timestamp: 1337966815
event: open
categories: olduser

小提琴:https://dotnetfiddle.net/lERrmu

编辑

如果你需要走另一种方式,即序列化,同时保持相同的格式,你可以实现的转换器的WriteJson()方法如下所示。 (确保删除CanWrite重写或更改它以返回true,否则WriteJson()将永远不会被调用。)

public override void WriteJson(JsonWriter writer,JsonSerializer serializer)
    {
        List<T> list = (List<T>)value;
        if (list.Count == 1)
        {
            value = list[0];
        }
        serializer.Serialize(writer,value);
    }

小提琴:https://dotnetfiddle.net/XG3eRy

猜你在找的Json相关文章