You need to enable JavaScript to run this app. 使用YamlDotNet根据操作类型动态调整YAML序列化输出属性名
优惠活动
大模型
产品
解决方案
定价
更多

使用YamlDotNet根据操作类型动态调整YAML序列化输出属性名

现有场景与需求

目前使用YamlDotNet处理对象序列化时,希望根据操作类型调整输出的YAML结构。

原有类定义

State.cs

public class State
{
    public string name { get; set; }
    public List<Operation> operations { get; set; }
}

Operation.cs

public class Operation
{
    public string name { get; set; }
    public string type { get; set; }
}

当前实际序列化输出

states:
- name: uPError
  operations:
  - name: switch on uP
    type: entry
  - name: switch off uP
    type: exit
  - name: test Do
    type: do

期望序列化输出

states:
- name: uPError
  entryActions: [switch on uP]
  exitActions: [switch off uP]
  doActions: [test Do]

核心问题

已经可以拿到所有操作的类型与对应名称,需要把原本的operations列表,按照操作类型拆分对应为entryActions、exitActions、doActions三个独立属性,绑定对应类型的操作名称输出,实现目标格式的转换。


实现方案

方案一:调整类结构适配序列化规则(最简单,推荐)

YamlDotNet默认会将类的公开属性映射为YAML节点,只要把原有的operations属性标记为忽略序列化,再新增三个按类型筛选操作的计算属性,就能直接输出目标格式,不需要写额外序列化逻辑:

  1. 引入依赖命名空间
    using YamlDotNet.Serialization;
    using System.Linq;
    
  2. 改造State类定义
    public class State
    {
        public string name { get; set; }
    
        // 标记原有operations属性不参与序列化,避免输出原始结构
        [YamlIgnore]
        public List<Operation> operations { get; set; }
    
        // 新增三个分类属性,指定输出为内联Flow序列格式(即[xxx]样式)
        [YamlMember(SequenceStyle = SequenceStyle.Flow)]
        public List<string> entryActions => 
            operations?.Where(op => op.type == "entry").Select(op => op.name).ToList() 
            ?? new List<string>();
    
        [YamlMember(SequenceStyle = SequenceStyle.Flow)]
        public List<string> exitActions => 
            operations?.Where(op => op.type == "exit").Select(op => op.name).ToList() 
            ?? new List<string>();
    
        [YamlMember(SequenceStyle = SequenceStyle.Flow)]
        public List<string> doActions => 
            operations?.Where(op => op.type == "do").Select(op => op.name).ToList() 
            ?? new List<string>();
    }
    
  3. 构建默认序列化器直接使用即可
    var serializer = new SerializerBuilder().Build();
    var yaml = serializer.Serialize(stateList);
    

方案二:自定义类型转换器(不想修改原有类结构时使用)

如果保留原有State类的定义,不新增属性,就通过实现YamlDotNet的IYamlTypeConverter接口,自定义State类型的序列化逻辑:

  1. 编写自定义转换器
    using YamlDotNet.Serialization;
    using YamlDotNet.Core;
    using YamlDotNet.Core.Events;
    using System.Linq;
    
    public class StateYamlConverter : IYamlTypeConverter
    {
        // 声明该转换器仅处理State类型
        public bool Accepts(Type type) => type == typeof(State);
    
        // 仅需要序列化的话,反序列化方法留空即可
        public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
        {
            throw new NotImplementedException();
        }
    
        public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer rootSerializer)
        {
            var state = (State)value;
            // 开始映射节点
            emitter.Emit(new MappingStart());
    
            // 输出name字段
            emitter.Emit(new Scalar("name"));
            emitter.Emit(new Scalar(state.name ?? string.Empty));
    
            // 按类型筛选对应操作名称
            var entryOps = state.operations?.Where(op => op.type == "entry").Select(op => op.name).ToList() ?? new List<string>();
            var exitOps = state.operations?.Where(op => op.type == "exit").Select(op => op.name).ToList() ?? new List<string>();
            var doOps = state.operations?.Where(op => op.type == "do").Select(op => op.name).ToList() ?? new List<string>();
    
            // 调用公共方法输出内联序列
            EmitInlineSequence(emitter, "entryActions", entryOps);
            EmitInlineSequence(emitter, "exitActions", exitOps);
            EmitInlineSequence(emitter, "doActions", doOps);
    
            emitter.Emit(new MappingEnd());
        }
    
        // 抽出公共的内联序列输出方法,减少重复代码
        private void EmitInlineSequence(IEmitter emitter, string key, List<string> items)
        {
            emitter.Emit(new Scalar(key));
            emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Flow));
            foreach (var item in items)
            {
                emitter.Emit(new Scalar(item));
            }
            emitter.Emit(new SequenceEnd());
        }
    }
    
  2. 注册转换器到序列化配置中使用
    var serializer = new SerializerBuilder()
        .WithTypeConverter(new StateYamlConverter())
        .Build();
    var yaml = serializer.Serialize(stateList);
    

注意事项
  • 如果分类后的操作列表为空,不想输出对应的空键,可以在构建序列化器时开启IgnorePropertiesWithDefaultValue选项,空列表会被自动跳过。
  • 代码里的操作类型字符串(entry/exit/do)建议抽成常量或枚举映射,避免硬编码拼写错误。
  • 一定要指定序列为*Flow(内联)*风格,否则YamlDotNet默认会输出块式序列,和期望的[xxx]内联格式不一致。

内容的提问来源于stack exchange,提问作者Priom Biswas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 01:06:04