11

使用 Newtonsoft,我们有一个用于忽略空集合的自定义解析器。.Net core 3.1 中的新 system.text.json 是否有任何等效配置

4

2 回答 2

1

有条件地忽略.NET5 官方How to migrate from Newtonsoft.Json to System.Text.Json from 2020 Dec 14 中的一个属性:

System.Text.Json 提供以下方式在序列化时忽略属性或字段:

  • [JsonIgnore] 属性 (...)。
  • IgnoreReadOnlyProperties 全局选项 (...)。
  • (...) JsonSerializerOptions.IgnoreReadOnlyFields 全局 (...)
  • DefaultIgnoreCondition 全局选项允许您忽略所有具有默认值的值类型属性,或忽略所有具有空值的引用类型属性。

这些选项不允许您:

  • 忽略基于在运行时评估的任意标准的选定属性。

对于该功能,您可以编写自定义转换器。这是一个示例 POCO 和一个自定义转换器,它说明了这种方法:

(下面是一个类型的自定义转换器示例)

请注意,此转换器需要是包含集合属性的类型的转换器,它不是集合类型的转换器(请参阅我的第二个答案)。

于 2021-04-09T13:50:45.020 回答
0

一次尝试

我知道这不是您所追求的,但也许有人可以在此基础上进行构建,或者它可能适合某些场景的可能性非常小。

我设法做到了

new A()一个对象

public class A
{
   public List<int> NullList {get;set;}
   public List<int> EmptyList {get;set;} = new List<int>();
};

变成

{
  "EmptyList": null
}

文档

How to write custom converters for JSON serialization (marshalling) in .NET from 2021 Feb 25 in Custom converter patterns说:

创建自定义转换器有两种模式:基本模式和工厂模式。工厂模式适用于处理类型 Enum 或开放泛型的转换器。基本模式适用于非泛型和封闭泛型类型。例如,以下类型的转换器需要工厂模式:

  • 字典<TKey,TValue>
  • 枚举
  • 列表

基本模式可以处理的一些类型示例包括:

  • 字典<int, string>
  • 平日枚举
  • 列表
  • 约会时间
  • 整数32

基本模式创建一个可以处理一种类型的类。工厂模式创建一个类,该类在运行时确定所需的特定类型并动态创建适当的转换器。

我做了什么

演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;

#nullable disable

namespace Sandbox4
{
 
    public class A
    {
        public List<int> NullList {get;set;}
        public List<int> EmptyList {get;set;} = new List<int>();
     };

    public class Program
    {
        public static void Main()
        {
            A a = new ();

            JsonSerializerOptions options = new ()
            {
                DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault,
                WriteIndented = true,
                Converters =
                {  
                     new IEnumerableTConverter()
                }
            };

            string aJson =
                JsonSerializer.Serialize<A>(a, options);
            
            Console.WriteLine(aJson);
        }
    }
}

转换器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Sandbox4
{
    // Modified DictionaryTEnumTValueConverter 
    // from https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#custom-converter-patterns
    public class IEnumerableTConverter : JsonConverterFactory
    {
        public override bool CanConvert(Type typeToConvert)
        {
            if (!typeToConvert.IsGenericType)
            {
                return false;
            }

            var realType = typeToConvert.GetGenericTypeDefinition();
            if (realType.IsAssignableTo(typeof(IEnumerable<>)))
            {
                return false;
            }
            return true;
        }

        public override JsonConverter CreateConverter(
            Type type,
            JsonSerializerOptions options)
        {
            Type generictype = type.GetGenericArguments()[0];

            JsonConverter converter = (JsonConverter)Activator.CreateInstance(
                typeof(ICollectionTConverterInner<,>).MakeGenericType(
                    new Type[] { type, generictype }),
                BindingFlags.Instance | BindingFlags.Public,
                binder: null,
                args: new object[] { type, options },
                culture: null);

            return converter;
        }

        private class ICollectionTConverterInner<T,U> :
            JsonConverter<T> where T: IEnumerable<U>
        {
            private readonly JsonConverter<T> _normalConverter;

            public ICollectionTConverterInner(Type type,JsonSerializerOptions options)
            {
                // For performance, use the existing converter if available.
                var existing = new JsonSerializerOptions().GetConverter(type);
                if( existing == null ) throw new ApplicationException($"Standard converter for {type} not found.");

                _normalConverter = (JsonConverter<T>) existing;
            }

            public override T Read(
                ref Utf8JsonReader reader,
                Type typeToConvert,
                JsonSerializerOptions options)
            {
                // Untested
                return _normalConverter.Read(ref reader, typeToConvert, options);
            }

            public override void Write(
                Utf8JsonWriter writer,
                T collection,
                JsonSerializerOptions options)
            {
                if(!collection.Any()) 
                {
                    writer.WriteNullValue();
                    return;
                }

                _normalConverter.Write(writer, collection, options);
            }
        }
    }
}
于 2021-04-09T14:44:06.380 回答