gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 18:24:46 25 4
gpt4 key购买 nike

我正在尝试修复我的 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com