
YamlDotNet读取YAML文件时抛出YamlException怎么办
常见原因是缩进不一致(混用空格与Tab)、键名后缺少冒号、或注释位置非法。YamlDotNet默认严格遵循YAML 1.2规范,不接受松散格式。
实操建议:
- 用VS Code装
YAML插件实时校验语法,启用"yaml.format.enable": true - 读取前先用
File.ReadAllText(path)打印原始字符串,确认无BOM头或不可见控制字符 - 若YAML含中文键或值,确保文件保存为UTF-8无BOM格式
- 捕获
YamlException时检查e.Message和e.Start,它会指出具体行号和列偏移
如何用Deserializer.Deserialize映射嵌套结构
YamlDotNet的反序列化依赖属性名称与YAML键名**完全匹配**(区分大小写),且类需有公共setter或使用[YamlMember(Alias = "...")]显式指定别名。
示例YAML片段:
server: host: localhost port: 8080 logging: level: Debug file: app.log
对应C#类需这样定义:
public class Config
{
public ServerConfig server { get; set; }
public LoggingConfig logging { get; set; }
}
public class ServerConfig
{
public string host { get; set; }
public int port { get; set; }
}
public class LoggingConfig
{
public string level { get; set; }
public string file { get; set; }
}
关键点:
- 所有属性必须是
public,字段(public string host;)不会被自动识别 - 若YAML中键为
log-level,C#属性需加[YamlMember(Alias = "log-level")] - 数组用
IList或T[]接收,不要用List(虽能工作但不推荐)
Serializer.Serialize输出格式难看?如何控制缩进与换行
默认序列化器不保留原始注释、不换行、缩进为2空格,且布尔值输出为True/False(非true/false)。
要生成更规范的YAML,需自定义Serializer:
var serializer = new SerializerBuilder()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull)
.WithNamingConvention(new CamelCaseNamingConvention()) // 或 NullNamingConvention保持原名
.WithEventEmitter(e => new MyCustomEventEmitter(e)) // 如需控制布尔/数字格式
.Build();
常用配置项:
-
.WithIndentedSequences():让列表每项独占一行(否则默认内联) -
.WithTypeConverter(new BooleanConverter()):强制输出小写true/false -
.EmitDefaults():输出值为null或默认值的字段(默认省略) - 避免直接调用
serializer.Serialize(writer, obj),改用serializer.Serialize(TextWriter, obj)防止编码问题
为什么修改对象后Serialize没更新YAML中的注释或顺序
YamlDotNet的Deserializer解析后生成的是纯对象图,原始YAML的注释、键顺序、引号风格等元信息全部丢失。它不是“编辑器”,而是“转换器”。
这意味着:
- 无法实现“只改一个字段,其余格式照旧”的精准编辑
- 若需保留注释,必须改用
YamlStream+YamlMappingNode等底层API手动遍历节点 - 键顺序默认按字典序排列,要保持YAML原有顺序,需用
Dictionary接收,再配合PreserveOrderingObjectGraphVisitor - 生产环境配置管理,建议将YAML仅作输入,运行时用强类型对象操作,导出时接受格式重排
Deserialize这种便利接口。










