【问题标题】:Custom Json.NET converter should not serialize a property自定义 Json.NET 转换器不应序列化属性
【发布时间】:2023-04-07 16:54:01
【问题描述】:

我编写了一个 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
}

我希望看到的输出:

{}

我该怎么做才能使属性被省略而不是为空?

P.S.:我已经阅读了条件属性序列化,但是 ShouldSerialize 方法不适合我的情况,我还没有弄清楚如何在我的情况下使用 IContractResolver。

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    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 应用于标记枚举。不要将此属性应用于简单的枚举。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-16
      • 2013-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-02
      • 1970-01-01
      相关资源
      最近更新 更多