要求。
对于 JSON 序列化json.net
:
- 将无效的双精度值(例如
double.NaN
)转换为null
。 - 使双倍变短(G3)。
- 不要写入带有
null
值的属性。
听起来简单吗?
显而易见的解决方案。
第一个和第二个是通过制作 json 转换器来完成的,对吗?
JsonSerializerSettings
第三个是使用with完成的NullValueHandling = NullValueHandling.Ignore
,对吗?
嗯,有一个问题,它们不能一起工作。如果值为null
,则转换器甚至不会被调用,很好。但如果转换器产生null
,则不会发生空值忽略。
试图。
下面是代码或者直接尝试重现。我应该怎么做?
static void Main(string[] args)
{
var test = new A(
d: 1.23456789,
nd1: 1.23456789,
nd2: null,
nd3: double.NaN,
da: [1.23456789],
nda: [1.23456789, null, double.NaN]);
var json = JsonConvert.SerializeObject(test, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Converters = { new MyJsonConverter() }
});
Console.WriteLine(json);
}
public class MyJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(double) || objectType == typeof(double?);
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value is double input && double.IsFinite(input))
writer.WriteRawValue(input.ToString("G3", NumberFormatInfo.InvariantInfo));
else
writer.WriteNull();
}
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) => throw new NotImplementedException();
}
public record A(
double d,
double? nd1,
double? nd2,
double? nd3,
double[] da,
double?[] nda)
{ }
输出:
{"d":1.23,"nd1":1.23,"nd3":null,"da":[1.23],"nda":[1.23,null,null]}
预期输出不包含nd3
:
{"d":1.23,"nd1":1.23,"da":[1.23],"nda":[1.23,null,null]}
PS:我想不出一个好的标题,因此询问如何解决我尝试的解决方案(XY 问题)。我认为这样的标题最能描述意图,有人可能会遇到类似的问题,其中转换器生成的值应该影响 json 属性。
为此,您需要将自定义转换逻辑与空值处理结合起来。您面临的问题是因为您的转换器生成的空值不会触发 NullValueHandling.Ignore 行为。这可以通过调整序列化对象的方式来解决。
自定义转换器:您的 MyJsonConverter 应该通过将 double.NaN 转换为 null 并使用 G3 格式格式化有效的双精度数来处理它,就像您已经做的那样。
自定义契约解析器:要跳过转换器生成的具有空值的属性,您可以使用自定义契约解析器。此解析器将从序列化过程中排除具有空值的属性。
代码:
预期输出:
通过这种方式,可以确保具有空值的属性(无论它们最初为空还是由自定义转换器转换为空)都被排除在 JSON 输出之外。