【问题标题】:Ignoring some default values for serialization忽略序列化的一些默认值
【发布时间】:2020-04-07 00:38:44
【问题描述】:

tl;博士;在 Newtonsoft JSON.NET 中,如何忽略某些类型(枚举)而不是其他类型(整数)的默认值?


我的团队正在使用一个为其业务实体使用协议缓冲区的库。这个库/protobuf 中的每个枚举都有一个默认值 0,即“ValueNotSet”。我的团队正在使用 Newtonsoft JSON.NET 来序列化这些实体。以下是面包店库存的稀释示例:

public enum Flavor { ValueNotSet, Cherry, Blueberry, Cheese };
public class DanishInventory { public int QtyInStock; public Flavor; }

为了节省资源,我们不想序列化ValueNotSet(现实世界的场景有很多枚举),但是零奶酪丹麦是有效的,我们确实想要序列化零.因此,我们不能在设置中使用 DefaultValueHandling = Ignore。

我创建了一个自定义 JsonConverter,但是在调用 WriteJson(...) 时,密钥已经在 J​​sonWriter 中。因此,如果我什么都不写,JSON 是无效的,并且我看不到一个明显的方法来回溯编写器以覆盖密钥。那么忽略某些类型(例如枚举)而不是其他类型(例如整数)的默认值的最佳方法是什么?

请注意,枚举位于 NuGet 包中,无法修改,例如通过添加属性。

【问题讨论】:

    标签: json.net protocol-buffers


    【解决方案1】:

    您可以使用从this answerJson.NET: How to make DefaultValueHandling only apply to certain types?DefaultValueContractResolver 的变体来排除所有具有默认值的枚举值属性:

    public class EnumDefaultValueContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            if (property.DefaultValueHandling == null)
            {
                if (property.PropertyType.IsEnum)
                {
                    //For safety you could check here if the default value is named ValueNotSet and only set IgnoreAndPopulate in that case.
                    //var defaultValue = Enum.ToObject(property.PropertyType, 0);
                    //if (defaultValue.ToString() == "ValueNotSet")
                    //{                 
                        property.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // Or DefaultValueHandling.Ignore if you prefer
                    //}
                }
            }
    
            return property;
        }
    }
    

    然后按如下方式使用:

    var resolver = new EnumDefaultValueContractResolver();
    
    var settings = new JsonSerializerSettings { ContractResolver = resolver };
    var json = JsonConvert.SerializeObject(inventory, settings);
    

    您可能想cache the contract resolver for best performance

    演示小提琴here.

    【讨论】:

      【解决方案2】:

      许多序列化程序(包括我相信的 Json.NET)支持 ShouldSerialize*() 模式;如果您不介意按使用情况执行此操作,您可以这样做:

      public class DanishInventory {
          public int QtyInStock;
          public Flavor;
          public bool ShouldSerializeFlavor() => Flavor != 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-10-27
        • 2016-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-06
        • 1970-01-01
        • 2015-11-15
        • 1970-01-01
        相关资源
        最近更新 更多