Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用JSON.NET序列化并忽略可为空的结构值_C#_.net_Json_Json.net_Jsonconverter - Fatal编程技术网

C# 如何使用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

我正在尝试使用JSON.NET和自定义的
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);
}
}
}

这里有三个问题:

  • 如至中所述:

    A无法阻止序列化其值,因为在调用转换器时,引用它的属性名称将已被写出。在Json.NET的体系结构中,包含类型负责决定序列化其哪些属性;然后,值转换器决定如何序列化正在写入的值

  • 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是不可变的,原因是

    中解释的原因。