ASP.NET Core MVC实现Field子类的多态JSON反序列化
在ASP.NET Core MVC中实现Field子类的JSON多态反序列化
要解决父类Field反序列化为对应子类(TextField/Checkbox)的问题,核心是通过自定义JSON转换器,根据JSON中的type字段或value的类型来判断并实例化正确的子类。以下是两种主流序列化库的实现方案:
方案一:使用默认的System.Text.Json
1. 自定义Field转换器
创建继承自JsonConverter<Field>的转换器,实现根据type字段选择子类的逻辑:
using System.Text.Json; using System.Text.Json.Serialization; public class FieldJsonConverter : JsonConverter<Field> { public override Field Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 读取JSON为文档,便于提取属性 using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // 获取type字段值 if (!root.TryGetProperty("type", out var typeElement)) { throw new JsonException("Field对象缺少必填的'type'属性"); } var fieldType = typeElement.GetString(); // 根据type匹配对应子类反序列化 return fieldType switch { "text" => JsonSerializer.Deserialize<TextField>(root.GetRawText(), options), "checkbox" => JsonSerializer.Deserialize<Checkbox>(root.GetRawText(), options), _ => throw new JsonException($"不支持的Field类型:{fieldType}") }; } public override void Write(Utf8JsonWriter writer, Field value, JsonSerializerOptions options) { // 序列化时自动识别实际子类类型 JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
2. 注册转换器
有两种注册方式可选:
- 方式一:在父类上标记特性(仅影响
Field类型)
[JsonConverter(typeof(FieldJsonConverter))] public class Field { public string type { get; set; } public bool filledIn { get; set; } }
- 方式二:全局注册(影响所有
Field类型的反序列化)
在Program.cs中添加:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new FieldJsonConverter()); });
3. 验证与使用
在控制器方法中,可通过类型判断处理不同子类:
public void ParseAndSave(Form myForm) { foreach (var field in myForm.fields) { switch (field) { case TextField textField: // 处理文本字段:textField.value 为字符串类型 break; case Checkbox checkbox: // 处理复选框:checkbox.value 为布尔类型 break; } } }
方案二:基于value类型判断(替代type字段)
如果不想依赖type字段,可通过value的JSON类型来判断子类,修改转换器的Read方法:
public override Field Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; if (root.TryGetProperty("value", out var valueElement)) { return valueElement.ValueKind switch { JsonValueKind.String => JsonSerializer.Deserialize<TextField>(root.GetRawText(), options), JsonValueKind.True or JsonValueKind.False => JsonSerializer.Deserialize<Checkbox>(root.GetRawText(), options), _ => throw new JsonException("无法通过value类型识别Field子类") }; } throw new JsonException("Field对象缺少value属性"); }
方案三:使用Newtonsoft.Json(Json.NET)
如果项目依赖Newtonsoft.Json,可创建对应的转换器:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class FieldNewtonsoftConverter : JsonConverter<Field> { public override Field ReadJson(JsonReader reader, Type objectType, Field existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var fieldType = jObject["type"]?.ToString(); return fieldType switch { "text" => jObject.ToObject<TextField>(serializer), "checkbox" => jObject.ToObject<Checkbox>(serializer), _ => throw new JsonException($"不支持的Field类型:{fieldType}") }; } public override void WriteJson(JsonWriter writer, Field value, JsonSerializer serializer) { serializer.Serialize(writer, value, value.GetType()); } }
全局注册方式:
builder.Services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new FieldNewtonsoftConverter()); });
内容的提问来源于stack exchange,提问作者Eric Webb
相关产品推荐
相关产品推荐

