我在反序列化 JSON 多态时遇到问题。这是一个最小的例子:
我有一个定义 JSON 类型的枚举:
public enum BlockType
{
T1,
T2
}
基类和子类(以及容器):
public class Container
{
required public List<BaseType> ListOfItems { get; set; }
}
[JsonPolymorphic(TypeDiscriminatorPropertyName = nameof(Type))]
[JsonDerivedType(typeof(Type1), nameof(BlockType.T1))]
[JsonDerivedType(typeof(Type2), nameof(BlockType.T2))]
public class BaseType
{
[JsonConverter(typeof(JsonStringEnumConverter))]
required public BlockType Type { get; set; }
}
public class Type1 : BaseType
{
required public int Value1 { get; set; }
}
public class Type2 : BaseType
{
required public int Value2 { get; set; }
}
我有一个输入 JSON:
var jsonBody = """
{
"ListOfItems": [
{
"type": "T1",
"Value1": 10
},
{
"type": "T2",
"Value2": 11
}
]
}
""";
并调用序列化器:
var deserializeOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
WriteIndented = true,
};
var decoded = JsonSerializer.Deserialize<Container>(jsonBody, deserializeOptions);
序列化器不会返回任何错误。但是,当我检查返回的类型和列表
Container.ListOfItems
时,其中的每个项目都是BaseType
,而不是派生的Type1
或Type2
。事实上,如果我投射该物体:
foreach (BaseType o in decoded.ListOfItems)
{
if (o.Type == BlockType.T1)
{
Type1 obj = (Type1)o;
}
}
我会得到一个
InvalidCastException: Cannot convert BaseType to Type1.
这个问题有解决办法吗?
我个人已经放弃使用[JsonPolymorphic],而是编写了一个转换器。上述类的转换器看起来像这样
public class BaseTypeConverter : JsonConverter<BaseType>
{
public override BaseType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var doc = JsonDocument.ParseValue(ref reader);
var typestr = doc.RootElement.GetProperty("type").GetString()?.ToUpper();
if (Enum.TryParse(typestr, out BlockType type)) {
if (type == BlockType.T1) {
return JsonSerializer.Deserialize<Type1>(doc.RootElement.GetRawText(), options);
}
else
{
return JsonSerializer.Deserialize<Type2>(doc.RootElement.GetRawText(), options);
}
}
}
public override void Write(Utf8JsonWriter writer, BaseType value, JsonSerializerOptions options)
{
// I'm only interested in deserializing
throw new NotImplementedException();
}
}
您的代码和属性中有一些错误。基本上反序列化无需自定义即可正常工作
JsonConverter
。
我可以建议您查看 2 个解决方案。
解决方案1:
请再次检查您的代码...
您尝试使用一种属性(类型)来检测实例类型和属性。 为此,您需要使用不同的 JSON 属性。
您可以将
JsonPolymorphic
属性更改为:
[JsonPolymorphic(TypeDiscriminatorPropertyName = "__type")]
在这种情况下,您的 JSON 字符串必须如下所示:
{
"ListOfItems": [
{
"__type": "T1",
"Type": "T1",
"Value1": 10
},
{
"__type": "T2",
"Type": "T2",
"Value2": 11
}
]
}
在这种情况下,通过值“__type”反序列化器将创建类的正确实例,并将正确填充属性类型(到您的枚举值)。
解决方案2:
您可能想重新设计您的类继承。看来类
BaseType
一定是抽象的。在这种情况下,您可以覆盖继承类中的属性 Type。
请查看那里的代码片段:
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(Type1), nameof(BlockType.T1))]
[JsonDerivedType(typeof(Type2), nameof(BlockType.T2))]
public abstract class BaseType
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public abstract BlockType Type { get; }
}
public class Type1 : BaseType
{
public override BlockType Type => BlockType.T1;
required public int Value1 { get; set; }
}
public class Type2 : BaseType
{
public override BlockType Type => BlockType.T2;
required public int Value2 { get; set; }
}
在这种情况下,您的 JSON 字符串将与您提供的相同。