自定义Json.NET转换器不应序列化属性

时间:2018-10-05 18:33:38

标签: c# json.net

我编写了一个Json.NET转换器,该转换器将所有设置的标志输出为数组。

enum SampleEnum
{
    None = 0,
    ValueA = 2,
    ValueB = 4
}

SampleEnum flags = SampleEnum.ValueA | SampleEnum.ValueB;
// JSON: ["ValueA", "ValueB"]

现在,如果flagsSampleEnum.None,则该属性不应被序列化。因此,我只是不向JsonWriter写任何东西。这是转换器的WriteJson方法的代码。

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    if (value is SampleEnum enumValue)
    {
        IEnumerable<SampleEnum> setFlags = GetSetFlags<SampleEnum>(enumValue);              

        IEnumerable<string> flagNames = setFlags
            .Where(flag => flag != SampleEnum.None) // Filter out 'None'
            .Select(flag => flag.ToString());

        if (flagNames.Any())
        {
            JArray jArray = JArray.FromObject(flagNames, serializer);
            jArray.WriteTo(writer);
        }
        // Else omit this property
    }
}

但是,如果我在类中具有SampleEnum类型的属性,并且其值为SampleEnum.None,则该属性将被序列化,并且JSON值为null。

class SerializedClass
{
    [JsonConverter(typeof(ArrayEnumConverter))]
    public SampleEnum EnumValue { get; set; }
}

SerializedClass obj = new SerializedClass
{
    EnumValue = SampleEnum.None
};
string json = JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore
});

输出如下:

{
  "EnumValue": null
}

我希望看到的输出:

{}

我该怎么做,以便该属性被忽略而不是为空?

PS:我已经了解了条件属性序列化,但是ShouldSerialize方法不适用于我的情况,我还没有弄清楚如何为我的情况使用IContractResolver。

1 个答案:

答案 0 :(得分:2)

custom JsonConverter不能阻止其值被序列化,因为引用该属性的属性名称将在调用转换器时被写出。在Json.NET的体系结构中,包含类型的责任是确定要序列化其属性的哪个。然后,值转换器决定如何对要写入的值进行序列化。

或者,即使应用了转换器,设置DefaultValueHandling.Ignore也可以用于跳过enum成员的序列化。由于SampleEnum.None的值为0,因此它是标志枚举的默认值。启用此设置(无论是否应用转换器)时,将跳过具有此值的成员。

您可以通过JsonPropertyAttribute.DefaultValueHandling来应用DefaultValueHandling

public class SerializedClass
{
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    [JsonConverter(typeof(ArrayEnumConverter))]
    public SampleEnum SampleEnum { get; set; }
}

提琴here

偶然地,您应该考虑使用[Flags]属性标记SampleEnum

[Flags]
public enum SampleEnum
{
    None = 0,
    ValueA = 2,
    ValueB = 4
}

这是标志枚举的recommended best practice

  

设计标志枚举

     

√确实将System.FlagsAttribute应用于标记枚举。不要将此属性应用于简单的枚举。