C# 如何使用JSON.NET序列化并忽略可为空的结构值
我正在尝试使用JSON.NET和自定义的C# 如何使用JSON.NET序列化并忽略可为空的结构值,c#,.net,json,json.net,jsonconverter,C#,.net,Json,Json.net,Jsonconverter,我正在尝试使用JSON.NET和自定义的JsonConverter序列化一个可为空的结构。我希望在JSON输出中忽略/省略null值,例如,我希望下面的JSON输出是{},而不是{“Number”:null}。如何做到这一点?这里是一个最小的复制,带有我试图实现的单元测试 [Fact] public void UnitTest() { int? number = null; var json = JsonConvert.SerializeObject( new E
JsonConverter
序列化一个可为空的结构。我希望在JSON输出中忽略/省略null
值,例如,我希望下面的JSON输出是{}
,而不是{“Number”:null}
。如何做到这一点?这里是一个最小的复制,带有我试图实现的单元测试
[Fact]
public void UnitTest()
{
int? number = null;
var json = JsonConvert.SerializeObject(
new Entity { Number = new HasValue<int?>(number) },
new JsonSerializerSettings()
{
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
});
Assert.Equal("{}", json); // Fails because json = {"Number":null}
}
public class Entity
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue<int?>? Number { get; set; }
}
public struct HasValue<T>
{
public HasValue(T value) => this.Value = value;
public object Value { get; set; }
}
public class NullJsonConverter : JsonConverter
{
public override bool CanRead => false;
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var values = (HasValue<int?>)value;
var objectValue = values.Value;
if (objectValue == null)
{
// How can I skip writing this property?
}
else
{
var token = JToken.FromObject(objectValue, serializer);
token.WriteTo(writer);
}
}
}
[事实]
公共空单元测试()
{
int?number=null;
var json=JsonConvert.SerializeObject(
新实体{Number=new HasValue(Number)},
新的JsonSerializerSettings()
{
DefaultValueHandling=DefaultValueHandling.Ignore,
NullValueHandling=NullValueHandling.Ignore
});
Assert.Equal(“{}”,json);//失败,因为json={“Number”:null}
}
公共类实体
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue?编号{get;set;}
}
公共结构HasValue
{
public HasValue(T值)=>this.value=value;
公共对象值{get;set;}
}
公共类NullJsonConverter:JsonConverter
{
public override bool CanRead=>false;
public override bool CanConvert(类型objectType)=>true;
public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)=>抛出新的NotImplementedException();
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
var值=(HasValue)值;
var objectValue=values.Value;
if(objectValue==null)
{
//如何跳过写入此属性?
}
其他的
{
var token=JToken.FromObject(objectValue,序列化程序);
token.WriteTo(writer);
}
}
}
这里有三个问题:
NullValueHandling.Ignore
不起作用,因为属性Entity.Number
为非null,它有一个值,即一个已分配的HasValue
结构,内部值为null
:
Number = new HasValue<int?>(number) // Not Number = null
public class Entity
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue<int?> Number { get; set; }
}
演示小提琴#1
然而,这种设计似乎有点过于复杂——您有一个包含结构的nullable,该结构封装了包含整数的nullable,即nullable
。您真的需要两个级别的nullable吗?如果没有,您只需删除外部的Nullable
,而DefaultValueHandling
现在将正常工作:
Number = new HasValue<int?>(number) // Not Number = null
public class Entity
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue<int?> Number { get; set; }
}
具体而言:
- 更改要键入的
属性值
- 添加非泛型接口以在序列化期间作为对象访问值
- 直接反序列化内部值,然后在反序列化期间调用参数化构造函数
[JsonConverter(typeof(NullJsonConverter))]
应用于HasValue
本身
您也可以考虑使<代码> HasValue/Cuth.Stutt是不可变的,原因是
中解释的原因。