给出以下多态类型层次结构:
[JsonConverter(typeof(PolymorphicConverter<Base>))]
public record Base
{
private Base() {}
public record A(string Value) : Base;
public record B(int Foobar) : Base;
public record C(Base Recursive) : Base;
}
使用所需的序列化 json,例如答:
{
"type": "A",
"content": {
"value": "jalla"
}
}
是否可以为 PolymorphicConverter 创建一个不依赖于类型
Base
、高性能且线程安全的实现?
这是一个有效且高性能的实现,但不是线程安全的:
using System;
using Newtonsoft.Json;
Base a = new Base.A("foobar");
var json = JsonConvert.SerializeObject(a);
Console.WriteLine(json);
[JsonConverter(typeof(PolymorphicConverter<Base>))]
public record Base
{
private Base() {}
public record A(string Value) : Base;
public record B(int Foobar) : Base;
public record C(Base Recursive) : Base;
}
public class PolymorphicConverter<TBase> : JsonConverter where TBase : class
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
var type = value?.GetType() ?? throw new NotImplementedException();
var converter = serializer.ContractResolver.ResolveContract(type).Converter;
serializer.ContractResolver.ResolveContract(type).Converter = null;
writer.WriteStartObject();
writer.WritePropertyName("type");
writer.WriteValue(type.Name);
writer.WritePropertyName("content");
serializer.Serialize(writer, value);
serializer.ContractResolver.ResolveContract(type).Converter = converter;
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return typeof(TBase).IsAssignableFrom(objectType);
}
}
您可以利用应用于属性的转换器取代应用于类型或设置中的转换器的记录功能来序列化包含您的
TBase
值的DTO,而不使用其应用的转换器:
public class PolymorphicConverter<TBase> : JsonConverter<TBase> where TBase : class
{
class DTO
{
[JsonProperty(Order = 1)]
public string? type { get; set; }
[JsonProperty(Order = 2, ReferenceLoopHandling = ReferenceLoopHandling.Serialize),
JsonConverter(typeof(NoConverter))]
public TBase? content { get; set; }
}
public override void WriteJson(JsonWriter writer, TBase? value, JsonSerializer serializer)
{
var type = value?.GetType() ?? throw new NotImplementedException();
serializer.Serialize(writer, new DTO { type = type.Name, content = value });
}
public override TBase? ReadJson(JsonReader reader, Type objectType, TBase? existingValue, bool hasExistingValue, JsonSerializer serializer) =>
throw new NotImplementedException();
}
public class NoConverter : JsonConverter
{
// NoConverter taken from this answer https://stackoverflow.com/a/39739105/3744182
// By https://stackoverflow.com/users/3744182/dbc
// To https://stackoverflow.com/questions/39738714/selectively-use-default-json-converter
public override bool CanConvert(Type objectType) => throw new NotImplementedException(); /* This converter should only be applied via attributes */
public override bool CanRead => false;
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => throw new NotImplementedException();
}
这消除了
serializer.ContractResolver.ResolveContract(type).Converter
到 null
的线程不安全设置。
备注:
通过从
false
和
CanRead
返回
CanWrite
,NoConverter
强制使用默认序列化。
JsonConverter<T>
纯粹是因为它简化了代码一点。
相关问题:
演示小提琴在这里。