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