c# - Newtonsoft JConverter读取对象或数组 (oneOf)
问题描述
我需要反序列化 JSON,其中发送者可以发送单个实例Child
作为节点之一,或者Child[]
. (又名 JsonSchema 'oneOf`)。
public class Parent
{
public Child[] Data { get; set; }
}
public class Child
{
public string ChildName { get; set; }
}
JSON可以是数组
{
"data":
[
{
"childName": "Bob"
}
]
}
或单个对象
{
"data":
{
"childName": "Bob"
}
}
这是我到目前为止所拥有的
public class ObjectToArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject singleJObject = (JObject)serializer.Deserialize(reader);
return new T[] { singleJObject.Value<T>() };
}
var arrayJObject = (JObject)serializer.Deserialize(reader);
return arrayJObject.Value<T[]>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
我这样使用
var settings = new JsonSerializerSettings();
settings.Converters.Add(new ObjectToArrayConverter<Child>());
var parent = JsonConvert.DeserializeObject<Parent>(json, settings);
但是当 JSONdata
节点是单个对象时,该行return new T[] { jObject.Value<T>() };
给了我异常
System.InvalidCastException:'无法将 Newtonsoft.Json.Linq.JObject 转换为 Newtonsoft.Json.Linq.JToken。'
当 JSONdata
节点是一个对象数组时,该行var arrayJObject = (JObject)serializer.Deserialize(reader);
给了我异常
System.InvalidCastException:'无法将'Newtonsoft.Json.Linq.JArray'类型的对象转换为'Newtonsoft.Json.Linq.JObject'类型。
解决方案
这里的问题是您使用的是扩展方法Value
而不是ToObject
. 值转换数据的“值”部分,因此在您的情况下为“鲍勃”。ToObject 将整个对象转换{"childName":"Bob"}
为提供的类。
return arrayJObject.ToObject<T[]>(); //This should work and...
return new T[] { singleJObject.ToObject<T>() };
另外,我建议改成这个 - 所以它会更具可读性
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var result = (JToken)serializer.Deserialize(reader);
if (result == null)
{
throw new ArgumentNullException(nameof(result));
}
if (result.Type == JTokenType.Object)
{
return new T[] { result.ToObject<T>() };
}
else if(result.Type == JTokenType.Array)
{
return result.ToObject<T[]>();
}
throw new NotSupportedException();
}
推荐阅读
- python - 使用条件识别行后的 Xlsxwriter 条件格式
- excel - 用VBA写这个公式
- android - 检查是否已安装自定义恢复
- java - 改造返回空数据
- python - 我可以通过 Docker compose 将两个 requirements.txt 文件合并为一个吗?
- xpath - 为了从网页中提取文本,XPath 被精确到一个?
- powerbi - 带过滤器的 PowerBi Dax 子查询
- php - 在 WooCommerce 中为 wp_dropdown_categories 下拉菜单启用 select2
- javascript - HTML Replace Select item with something more formatable
- c# - 处理在不同线程中读取的 TCP Socket 数据