YAML中抽象类反序列化:无需额外字段的实现方案咨询
无需额外字段实现YAML反序列化抽象类列表的方案
当然可以不用在AbstractAbility中添加AbilityType字段,下面是几种可行的实现方式:
1. 利用YAML序列化库的内置多态支持
大部分主流YAML库(比如YamlDotNet、结合Newtonsoft.Json的YAML序列化器)都原生支持多态类型的序列化/反序列化,不需要手动维护类型标识。
示例:YamlDotNet的特性标记法
给抽象基类添加[YamlInclude]特性,明确指定所有派生类:
using YamlDotNet.Serialization; [YamlInclude(typeof(StompAbility))] [YamlInclude(typeof(TeleportAbility))] public abstract class AbstractAbility { } public class StompAbility : AbstractAbility { public int Damage { get; set; } } public class TeleportAbility : AbstractAbility { public Vector3 TargetPosition { get; set; } }
然后配置反序列化器:
var deserializer = new DeserializerBuilder() .Build(); // 直接反序列化,库会自动识别派生类 var abilities = deserializer.Deserialize<List<AbstractAbility>>(yamlContent);
示例:Newtonsoft.Json+YAML的类型自动处理
如果用Newtonsoft.Json的YAML扩展,可通过开启TypeNameHandling让库自动在YAML中嵌入类型信息:
using Newtonsoft.Json; using YamlDotNet.Serialization; var jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto // 仅在必要时嵌入类型信息 }; var yamlDeserializer = new DeserializerBuilder() .WithJsonSerializerSettings(jsonSettings) .Build(); var abilities = yamlDeserializer.Deserialize<List<AbstractAbility>>(yamlContent);
2. 自定义类型解析器(灵活控制)
如果需要完全自定义类型判断逻辑(比如根据能力的特有属性识别类型),可以编写自定义类型转换器:
using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; public class AbilityTypeConverter : ITypeConverter { public bool Accepts(Type type, Type objectType) { return objectType == typeof(AbstractAbility); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer nestedObjectDeserializer) { // 读取YAML的映射节点 parser.Consume<MappingStart>(); var props = new Dictionary<string, object>(); while (parser.Current is Scalar scalar) { var key = scalar.Value; parser.MoveNext(); props[key] = nestedObjectDeserializer(typeof(object)); } parser.Consume<MappingEnd>(); // 根据特有属性判断类型 if (props.ContainsKey("Damage")) { return new StompAbility { Damage = (int)props["Damage"] }; } else if (props.ContainsKey("TargetPosition")) { return new TeleportAbility { TargetPosition = (Vector3)props["TargetPosition"] }; } throw new InvalidOperationException("无法识别的能力类型"); } public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer nestedObjectSerializer) { // 序列化逻辑按需实现,这里直接委托给默认序列化 nestedObjectSerializer(value); } }
注册并使用该转换器:
var deserializer = new DeserializerBuilder() .WithTypeConverter(new AbilityTypeConverter()) .Build(); var abilities = deserializer.Deserialize<List<AbstractAbility>>(yamlContent);
3. 配置文件层面的类型映射(可选)
如果允许配置文件中包含类型标识(但不需要在实体类中加字段),可以在YAML中给每个能力节点添加一个Type字段,反序列化时先读取该字段,再通过反射实例化对应的类:
示例YAML内容:
- Type: StompAbility Damage: 50 - Type: TeleportAbility TargetPosition: { X: 10, Y: 0, Z: 20 }
反序列化逻辑:
var rawAbilities = deserializer.Deserialize<List<Dictionary<string, object>>>(yamlContent); var abilities = new List<AbstractAbility>(); foreach (var raw in rawAbilities) { var typeName = (string)raw["Type"]; var type = Type.GetType($"YourNamespace.{typeName}"); var ability = (AbstractAbility)Activator.CreateInstance(type); // 手动赋值属性,或者用反射批量赋值 if (type == typeof(StompAbility)) { ((StompAbility)ability).Damage = (int)raw["Damage"]; } // 其他类型同理 abilities.Add(ability); }
内容的提问来源于stack exchange,提问作者Who am I
相关产品推荐
相关产品推荐

