Newtonsoft.Json 与 System.Text.Json 序列化时如何省略空集合

最近项目中有一个比较特殊的需求,在返回给前端树形json数据时,将等于NULL和集合count等于0的设置为忽略序列化;由于返回数据中集合较多,一时间没有太好的方案,于是开始在递归方法中处理数据,将集合数据为空或集合为0的数据赋值为NULL,但是实践过程不是很理想,于是翻看一些资料。

首先,介绍一下Newtonsoft.Json:

方案一:

如果您正在寻找一种可以在不同类型中通用且不需要任何修改(属性等)的解决方案,那么我认为最好的解决方案是自定义DefaultContractResolver类。它将使用反射来确定IEnumerable给定类型的任何值是否为空,代码如下:

public class IgnoreEmptyEnumerablesResolver : DefaultContractResolver
{
    public static readonly IgnoreEmptyEnumerablesResolver Instance = new IgnoreEmptyEnumerablesResolver();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (property.PropertyType != typeof(string) &&
            typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
        {
            property.ShouldSerialize = instance =>
            {
                IEnumerable enumerable = null;

                // this value could be in a public field or public property
                switch (member.MemberType)
                {
                    case MemberTypes.Property:
                        enumerable = instance
                            .GetType()
                            .GetProperty(member.Name)
                            .GetValue(instance, null) as IEnumerable;
                        break;
                    case MemberTypes.Field:
                        enumerable = instance
                            .GetType()
                            .GetField(member.Name)
                            .GetValue(instance) as IEnumerable;
                        break;
                    default:
                        break;

                }

                if (enumerable != null)
                {
                    // check to see if there is at least one item in the Enumerable
                    return enumerable.GetEnumerator().MoveNext();
                }
                else
                {
                    // if the list is null, we defer the decision to NullValueHandling
                    return true;
                }

            };
        }

        return property;
    }
}

您可以在您的框架的定制契约解析器中实现这个功能,此方案无需修改的你的代码,此方法相当于一些助手方法。

方案二:
如果您可以修改您的类,您可以添加封装方法并为所有空集合设置 NULL。它需要更改类,但它具有更好的性能。可能是您的另一种选择,代码如下:

  private List<JcLwtVM> lwtpChildren;

        [Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public List<JcLwtVM> lwtChildren
        {
            get { return lwtpChildren; }
            set { lwtpChildren = value == null || value.Count <= 0 ? null : value; }
        }

最终我采用上面的方案二,修改我得VM实体类属性代码,目前在应用中没有出现问题。

其次,System.Text.Json:

测试试图弄清楚如何序列化为json对象,并跳过序列化值为空列表的属性。测试没有使用Newtonsoft json。

封装有一个带有属性的对象:

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("hlfj")] public List<YjjcHlfjVM> HlfjList { get; set; }

在我测试中尝试使用以下命令序列化此对象时:

var optionsJson =   new JsonSerializerOptions
    {
    WriteIndented = true,
    IgnoreNullValues = true,
    PropertyNameCaseInsensitive = true,
    };

var json = JsonSerializer.Serialize(HlfjList, optionsJson);

结果中仍然给我一个空数组:"HlfjList": [],难道没有方法或属性阻止它序列化这些空列表吗?我不希望看到HlfjList集合,因为前端也不希望看到,所以空集合根本不应该出现在json数据里。我需要怎么做呢?

经过一番比对查找代码后发现JsonIgnoreCondition.WhenWritingNull这个属性,于是修改代码再次尝试:

1.添加具有相同签名的新属性,但使用JsonPropertyNameAttribute标记它,以确保使用正确的名称对其进行序列化,并使用JsonIgnoreAttribute进行序列化,以便在返回null时不会对其进行序列化。
2.用JsonIgnore标记的原始属性是无条件的,这样它就永远不会被序列化
3.当实际属性包含空列表时,这个伪属性将返回null(因此被忽略),否则它将返回(non-empty)列表
4.写入虚拟属性只是写入实际属性

代码如下:

[JsonIgnore]
public List<YjjcHlfjVM> HlfjList { get; set; } = new();

[JsonPropertyName("HlfjList")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
 public List<YjjcHlfjVM> HlfjListExtensions
    {
        get => HlfjList?.Count > 0 ? HlfjList : null;
        set => HlfjList = value ?? new();
    }

至此,测试结束,希望对有用到的小伙伴们有帮助,如果您有更好的方案请留言给我。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用如下代码实现: ``` using Newtonsoft.Json; using System.Collections.Generic; public class MyDictionaryConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var dictionary = (IDictionary)value; var keyType = dictionary.GetType().GetGenericArguments()[0]; var valueType = dictionary.GetType().GetGenericArguments()[1]; writer.WriteStartObject(); foreach (var key in dictionary.Keys) { writer.WritePropertyName(JsonConvert.SerializeObject(key)); serializer.Serialize(writer, dictionary[key]); } writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var dictionary = (IDictionary)Activator.CreateInstance(objectType); var keyType = objectType.GetGenericArguments()[0]; var valueType = objectType.GetGenericArguments()[1]; while (reader.Read() && reader.TokenType == JsonToken.PropertyName) { var propertyName = JsonConvert.DeserializeObject(reader.Value.ToString(), keyType); var value = serializer.Deserialize(reader, valueType); dictionary.Add(propertyName, value); } return dictionary; } } ``` 使用方法如下: ``` // 序列 Dictionary<string, object> dic = new Dictionary<string, object>(); string json = JsonConvert.SerializeObject(dic, new MyDictionaryConverter()); // 反序列 Dictionary<string, object> result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, new MyDictionaryConverter()); ``` 需要注意的是,需要在属性上添加 `[JsonConverter(typeof(MyDictionaryConverter))]` 特性来告诉 `Newtonsoft.Json` 使用上述自定义的 `MyDictionaryConverter` 来进行序列和反序列

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值