我正在尝试序列化
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
这是 .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]
。
演示小提琴在这里。