C#如何在SkillConverter中使用SkillEffectConverter反序列化嵌套多态对象
解决嵌套基类反序列化时的转换器调用问题
一、Newtonsoft.Json的可行方案
你之前的崩溃大概率是因为在SkillConverter中手动处理Effects属性时,没有调用已实现的SkillEffectConverter,导致多态类型无法正确识别。核心解决思路是:在SkillConverter的ReadJson方法中,利用当前JsonSerializer实例的Populate方法完成属性填充,让序列化器自动调用已配置的SkillEffectConverter处理嵌套的SkillEffect类型。
完整可运行代码
Part 1:正常工作的SkillEffect基类及转换器
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; // SkillEffect基类与子类 public abstract class SkillEffect { public string EffectType { get; set; } } public class DamageEffect : SkillEffect { public int Damage { get; set; } } public class SlowEffect : SkillEffect { public float SlowPercent { get; set; } } // SkillEffect自定义转换器 public class SkillEffectConverter : CustomCreationConverter<SkillEffect> { public override SkillEffect Create(Type objectType) { throw new NotImplementedException("Create无需直接调用,使用ReadJson处理实例创建"); } public override bool CanWrite => false; // 仅处理反序列化 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var effectType = jObject["EffectType"].Value<string>(); var effect = effectType switch { "Damage" => new DamageEffect(), "Slow" => new SlowEffect(), _ => throw new JsonSerializationException($"未知效果类型: {effectType}") }; // 用序列化器填充属性,确保所有字段被正确反序列化 serializer.Populate(jObject.CreateReader(), effect); return effect; } }
Part 2:修复后的Skill基类及转换器(原崩溃代码的修复版)
// Skill基类与子类 public abstract class Skill { public string SkillType { get; set; } public List<SkillEffect> Effects { get; set; } = new List<SkillEffect>(); } public class ProjectileSkill : Skill { public float Speed { get; set; } public float Range { get; set; } } // Skill自定义转换器 public class SkillConverter : CustomCreationConverter<Skill> { public override Skill Create(Type objectType) { throw new NotImplementedException("Create无需直接调用,使用ReadJson处理实例创建"); } public override bool CanWrite => false; public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var skillType = jObject["SkillType"].Value<string>(); var skill = skillType switch { "Projectile" => new ProjectileSkill(), _ => throw new JsonSerializationException($"未知技能类型: {skillType}") }; // 关键:使用serializer.Populate自动调用已配置的SkillEffectConverter处理Effects serializer.Populate(jObject.CreateReader(), skill); return skill; } }
测试代码
class Program { static void Main(string[] args) { // 配置序列化器,添加两个转换器 var settings = new JsonSerializerSettings(); settings.Converters.Add(new SkillEffectConverter()); settings.Converters.Add(new SkillConverter()); // 测试JSON var json = @" { ""SkillType"": ""Projectile"", ""Speed"": 10.0, ""Range"": 50.0, ""Effects"": [ { ""EffectType"": ""Damage"", ""Damage"": 20 }, { ""EffectType"": ""Slow"", ""SlowPercent"": 0.5 } ] }"; // 反序列化(修复后无崩溃) var skill = JsonConvert.DeserializeObject<Skill>(json, settings); if (skill is ProjectileSkill projectile) { Console.WriteLine($"投射技能:速度={projectile.Speed},射程={projectile.Range}"); foreach (var effect in projectile.Effects) { switch (effect) { case DamageEffect de: Console.WriteLine($"伤害效果:{de.Damage}点"); break; case SlowEffect se: Console.WriteLine($"减速效果:{se.SlowPercent:P0}"); break; } } } } }
崩溃原因说明
如果之前的SkillConverter中手动用jObject["Effects"].ToObject<List<SkillEffect>>()处理嵌套属性,而没有传入配置了SkillEffectConverter的JsonSerializerSettings,就会因为Newtonsoft无法识别SkillEffect的子类而抛出类型转换异常。使用serializer.Populate则会自动复用当前序列化器已配置的所有转换器,正确处理嵌套的多态类型。
二、替代方案:System.Text.Json
如果Newtonsoft.Json的方案不符合需求,可以使用.NET内置的System.Text.Json,它原生支持多态反序列化,无需手动编写转换器,实现更简洁:
using System.Text.Json; using System.Text.Json.Serialization; // 配置SkillEffect多态鉴别器 [JsonDerivedType(typeof(DamageEffect), typeDiscriminator: "Damage")] [JsonDerivedType(typeof(SlowEffect), typeDiscriminator: "Slow")] public abstract class SkillEffect { public string EffectType { get; set; } } public class DamageEffect : SkillEffect { public int Damage { get; set; } } public class SlowEffect : SkillEffect { public float SlowPercent { get; set; } } // 配置Skill多态鉴别器 [JsonDerivedType(typeof(ProjectileSkill), typeDiscriminator: "Projectile")] public abstract class Skill { public string SkillType { get; set; } public List<SkillEffect> Effects { get; set; } = new List<SkillEffect>(); } public class ProjectileSkill : Skill { public float Speed { get; set; } public float Range { get; set; } } // 测试代码 class Program { static void Main(string[] args) { var json = @" { ""SkillType"": ""Projectile"", ""Speed"": 10.0, ""Range"": 50.0, ""Effects"": [ { ""EffectType"": ""Damage"", ""Damage"": 20 }, { ""EffectType"": ""Slow"", ""SlowPercent"": 0.5 } ] }"; var skill = JsonSerializer.Deserialize<Skill>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); // 后续使用逻辑与之前一致 } }
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

