You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:23:10