JsonConverterAttribute 不被 JsonSerializer 使用

问题描述 投票:0回答:1

我正在尝试序列化

Encoding
类型的属性。我为此目的编写了一个转换器类。当我使用
JsonSerializerOptions
时,一切正常,但当我使用
JsonConverterAttribute
时,出现异常。我不确定我使用时做错了什么
JsonConverterAttribute
所以我希望得到你的帮助。

示例代码和异常:

using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace TestJsonConverterBug
{
    internal class Program
    {
        static readonly JsonSerializerOptions _options = new();

        static void Main()
        {
            _options.Converters.Add(new JsonEncodingConverter());

            TestOptions();
            TestAttributeSerialize();
            TestAttributeDeserialize();
        }

        // WORKS WITH OPTIONS
        static void TestOptions()
        {
            var obj = new SerializableClass1();

            var json = JsonSerializer.Serialize(obj, _options);

            var enc = JsonSerializer.Deserialize<SerializableClass1>(json, _options);
        }

        // DOESN'T WORK WITH CONVERTER ATTRIBUTE
        static void TestAttributeSerialize()
        {
            var obj = new SerializableClass2();

            var json = JsonSerializer.Serialize(obj);
        }

        // DOESN'T WORK WITH CONVERTER ATTRIBUTE
        static void TestAttributeDeserialize()
        {
            var obj = new SerializableClass2();

            var json = JsonSerializer.Serialize(obj, _options);

            var enc = JsonSerializer.Deserialize<SerializableClass2>(json);
        }
    }

    internal class SerializableClass1
    {
        public SerializableClass1()
        {
            Encoding = Encoding.ASCII;
        }

        public Encoding Encoding { get; set; }
    }

    internal class SerializableClass2
    {
        public SerializableClass2()
        {
            Encoding = Encoding.ASCII;
        }

        [JsonConverter(typeof(JsonEncodingConverter))]
        public Encoding Encoding { get; set; }
    }

    internal class JsonEncodingConverter : JsonConverter<Encoding>
    {
        public override bool CanConvert(Type typeToConvert)
            => typeToConvert.IsAssignableTo(typeof(Encoding));

        public override Encoding? Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options
        ) => Encoding.GetEncoding(reader.GetString()!);

        public override void Write(
            Utf8JsonWriter writer,
            Encoding value,
            JsonSerializerOptions options
        ) => writer.WriteStringValue(value.EncodingName);
    }
}

TestAttributeSerialize 异常:

System.InvalidOperationException
  HResult=0x80131509
  Message=The type 'System.ReadOnlySpan`1[System.Byte]' of property 'Preamble' on type 'System.Text.Encoding' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(Type typeToConvert, Type declaringType, MemberInfo memberInfo)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreatePropertyInfo(JsonTypeInfo typeInfo, Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options, Boolean shouldCheckForRequiredKeyword, Boolean hasJsonIncludeAttribute)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.AddMembersDeclaredBySuperType(JsonTypeInfo typeInfo, Type currentType, Boolean constructorHasSetsRequiredMembersAttribute, PropertyHierarchyResolutionState& state)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.PopulateProperties(JsonTypeInfo typeInfo)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateTypeInfoCore(Type type, JsonConverter converter, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
   at System.Text.Json.JsonSerializerOptions.CachingContext.CreateCacheEntry(Type type, CachingContext context)
--- End of stack trace from previous location ---
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.ConfigureProperties()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureSynchronized|172_0()
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoForRootType(Type type, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
   at TestJsonConverterBug.Program.TestAttributeSerialize() in ...\TestJsonConverterBug\Program.cs:line 35
   at TestJsonConverterBug.Program.Main() in ...\TestJsonConverterBug\Program.cs:line 16

TestAttribute反序列化异常:

System.InvalidOperationException
  HResult=0x80131509
  Message=The type 'System.ReadOnlySpan`1[System.Byte]' of property 'Preamble' on type 'System.Text.Encoding' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(Type typeToConvert, Type declaringType, MemberInfo memberInfo)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreatePropertyInfo(JsonTypeInfo typeInfo, Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options, Boolean shouldCheckForRequiredKeyword, Boolean hasJsonIncludeAttribute)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.AddMembersDeclaredBySuperType(JsonTypeInfo typeInfo, Type currentType, Boolean constructorHasSetsRequiredMembersAttribute, PropertyHierarchyResolutionState& state)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.PopulateProperties(JsonTypeInfo typeInfo)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateTypeInfoCore(Type type, JsonConverter converter, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
   at System.Text.Json.JsonSerializerOptions.CachingContext.CreateCacheEntry(Type type, CachingContext context)
--- End of stack trace from previous location ---
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.ConfigureProperties()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureSynchronized|172_0()
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoForRootType(Type type, Boolean fallBackToNearestAncestorType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at TestJsonConverterBug.Program.TestAttributeDeserialize() in ...\TestJsonConverterBug\Program.cs:line 45
   at TestJsonConverterBug.Program.Main() in ...\TestJsonConverterBug\Program.cs:line 17
c# json system.text.json c#-8.0
1个回答
0
投票

这是 .NET 8 中的一个已知回归,已报告。参见:

这似乎是[重大更改]中提到的故意重大更改的意外副作用:System.Text.Json 基于反射的反序列化器正在急切地解析所有属性元数据#37041。在该期中,MSFT 的 Eirik Tsarpalis 建议:

删除不支持的属性,为不支持的类型编写自定义转换器,或者像这样添加 JsonIgnoreAttribute...

由于添加转换器不起作用,您可以使用

Encoding
标记
[JsonIgnore]
属性,并使用编码名称添加代理
string
属性:

internal class SerializableClass2
{
    public SerializableClass2()
    {
        Encoding = Encoding.ASCII;
    }

    [JsonInclude, JsonPropertyName("Encoding")]
    string EncodingName { get => Encoding?.EncodingName!; set => Encoding = Encoding.GetEncoding(value); }

    [JsonIgnore]
    public Encoding Encoding { get; set; }
}

代理可以是私人的,只要标有

[JsonInclude]

演示小提琴在这里

© www.soinside.com 2019 - 2024. All rights reserved.