如何将带有空值的 json 数组反序列化为带有 JSON.NET 的不可为空的 int 列表?
How to deserialize json array with nulls to non-nullable int list with JSON.NET?
json 的以下部分给我带来了麻烦:
"edges":["5","","5",""]}
我正在尝试反序列化为以下 属性:
public class Redacted
{
...
[JsonProperty("edges", NullValueHandling = NullValueHandling.Ignore)]
public List<int> Edges { get; set; } = new();
...
}
然而,这给了我以下错误:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Error converting value {null} to type 'System.Int32'. Path 'edges[1]', line 1, position 186.
Source=Newtonsoft.Json
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at REDACTED.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in REDACTED.cs:line 45
This exception was originally thrown at this call stack:
System.Convert.ChangeType(object, System.Type, System.IFormatProvider)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(Newtonsoft.Json.JsonReader, object, System.Globalization.CultureInfo, Newtonsoft.Json.Serialization.JsonContract, System.Type)
Inner Exception 1:
InvalidCastException: Null object cannot be converted to a value type.
我试图在我的模型中指定 NullValueHandling.Ignore
但这似乎只适用于 属性 而不是列表中的项目。
我宁愿不必在设置中设置 NullValueHandling.Ignore
,它应该只适用于这个特定的 属性。
如何将此 json 反序列化为 List<int>
?
由于您使用的是 Json.NET,因此您可以构建一个自定义转换器来处理空 string
并将它们转换为 int
。这是一个开始:
public class NullableStringToIntConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(List<string>) == objectType;
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var items = serializer.Deserialize<List<string>>(reader);
return items
.Where(s => !string.IsNullOrEmpty(s))
.Select(int.Parse)
.ToList();
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要反序列化的 class 看起来像这样:
public class Thing
{
[JsonConverter(typeof(NullableStringToIntConverter))]
public List<int> Edges { get; set; }
}
最后反序列化:
var thing = JsonConvert.DeserializeObject<Thing>(json);
您可以添加边 属性 作为构造函数输入参数,而不是创建自定义转换器(您不需要将所有属性添加到构造函数)
Redacted redacted=JsonConvert.DeserializeObject<Redacted>(json);
public class Redacted
{
[JsonProperty("edges")]
public List<int> Edges { get; set; }
[JsonConstructor]
public Redacted(List<string> edges)
{
Edges=edges.Where(e=>!string.IsNullOrEmpty(e)).Select(e => Convert.ToInt32(e)).ToList();
}
public Redacted()
{
}
}
int-like 值列表转换器的另一个起点(允许空字符串、空值和整数值):
class SkipEmptyIntValuesListConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => false;
public override object ReadJson(
JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var list = new List<int>();
if (reader.TokenType == JsonToken.StartArray)
{
var value = reader.ReadAsInt32();
while (reader.TokenType != JsonToken.EndArray)
{
if (value.HasValue)
{
list.Add(value.Value);
}
value = reader.ReadAsInt32();
}
}
return list;
}
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
用法:
var json = "{\"edges\":[\"5\",\"\", 42, null]}";
var r = JsonConvert.DeserializeObject<Redacted>(json);
Console.Write(JsonConvert.SerializeObject(r)); // {"edges":[5,42]}
// Define other methods and classes here
public class Redacted
{
[JsonProperty("edges")]
[JsonConverter(typeof(SkipEmptyIntValuesListConverter))]
public List<int> Edges { get; set; }
}
json 的以下部分给我带来了麻烦:
"edges":["5","","5",""]}
我正在尝试反序列化为以下 属性:
public class Redacted
{
...
[JsonProperty("edges", NullValueHandling = NullValueHandling.Ignore)]
public List<int> Edges { get; set; } = new();
...
}
然而,这给了我以下错误:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Error converting value {null} to type 'System.Int32'. Path 'edges[1]', line 1, position 186.
Source=Newtonsoft.Json
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at REDACTED.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in REDACTED.cs:line 45
This exception was originally thrown at this call stack:
System.Convert.ChangeType(object, System.Type, System.IFormatProvider)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(Newtonsoft.Json.JsonReader, object, System.Globalization.CultureInfo, Newtonsoft.Json.Serialization.JsonContract, System.Type)
Inner Exception 1:
InvalidCastException: Null object cannot be converted to a value type.
我试图在我的模型中指定 NullValueHandling.Ignore
但这似乎只适用于 属性 而不是列表中的项目。
我宁愿不必在设置中设置 NullValueHandling.Ignore
,它应该只适用于这个特定的 属性。
如何将此 json 反序列化为 List<int>
?
由于您使用的是 Json.NET,因此您可以构建一个自定义转换器来处理空 string
并将它们转换为 int
。这是一个开始:
public class NullableStringToIntConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(List<string>) == objectType;
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var items = serializer.Deserialize<List<string>>(reader);
return items
.Where(s => !string.IsNullOrEmpty(s))
.Select(int.Parse)
.ToList();
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要反序列化的 class 看起来像这样:
public class Thing
{
[JsonConverter(typeof(NullableStringToIntConverter))]
public List<int> Edges { get; set; }
}
最后反序列化:
var thing = JsonConvert.DeserializeObject<Thing>(json);
您可以添加边 属性 作为构造函数输入参数,而不是创建自定义转换器(您不需要将所有属性添加到构造函数)
Redacted redacted=JsonConvert.DeserializeObject<Redacted>(json);
public class Redacted
{
[JsonProperty("edges")]
public List<int> Edges { get; set; }
[JsonConstructor]
public Redacted(List<string> edges)
{
Edges=edges.Where(e=>!string.IsNullOrEmpty(e)).Select(e => Convert.ToInt32(e)).ToList();
}
public Redacted()
{
}
}
int-like 值列表转换器的另一个起点(允许空字符串、空值和整数值):
class SkipEmptyIntValuesListConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => false;
public override object ReadJson(
JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var list = new List<int>();
if (reader.TokenType == JsonToken.StartArray)
{
var value = reader.ReadAsInt32();
while (reader.TokenType != JsonToken.EndArray)
{
if (value.HasValue)
{
list.Add(value.Value);
}
value = reader.ReadAsInt32();
}
}
return list;
}
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
用法:
var json = "{\"edges\":[\"5\",\"\", 42, null]}";
var r = JsonConvert.DeserializeObject<Redacted>(json);
Console.Write(JsonConvert.SerializeObject(r)); // {"edges":[5,42]}
// Define other methods and classes here
public class Redacted
{
[JsonProperty("edges")]
[JsonConverter(typeof(SkipEmptyIntValuesListConverter))]
public List<int> Edges { get; set; }
}