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

标签 c# json json.net sendgrid

我正在尝试修复我的 SendGridPlus 库以处理 SendGrid 事件,但我遇到了 API 中类别处理不一致的问题。

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

[
  {
    "email": "john.doe@sendgrid.com",
    "timestamp": 1337966815,
    "category": [
      "newuser",
      "transactional"
    ],
    "event": "open"
  },
  {
    "email": "jane.doe@sendgrid.com",
    "timestamp": 1337966815,
    "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"",
            ""timestamp"": 1337966815,
            ""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

fiddle :https://dotnetfiddle.net/lERrmu

编辑

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

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

fiddle :https://dotnetfiddle.net/XG3eRy

关于c# - 如何使用 JSON.net 处理同一属性的单个项目和数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30880637/

相关文章:

c# - 使用 C++/CLI 的任务并行库 Task.ContinueWith

java - jpa 和 java bean 外键验证

c# - 如何将缺少的 json 字段反序列化为 null?

c# - 使用 Json.Net 处理数据中的换行符

C# 我可以使用部分类来使代码更具可读性吗

c# - WMI:RPC 服务器不可用。 (HRESULT 异常:0x800706BA)尝试连接到远程机器时抛出

json - 创建 Visual Studio Code 扩展以实现自定义语言的语法突出显示

json - 如何在 Ubuntu webhook 命令上设置 webhook 密码?

c# - 包含类列表的类的 JSON.NET 反序列化

c# - 延迟加载 EF Core 2.1 不适用于身份?