
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<t></t>
映射嵌套结构
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></t>或
T[]接收,不要用
List<t></t>(虽能工作但不推荐)
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<string object></string>接收,再配合
PreserveOrderingObjectGraphVisitor生产环境配置管理,建议将YAML仅作输入,运行时用强类型对象操作,导出时接受格式重排 实际项目里最容易卡住的,是把YAML当INI用却忘了它本质是数据序列化格式——缩进即结构、空格Tab不能混、注释不可编程访问。真要双向保形编辑,得切到AST层,而不是依赖
Deserialize<t></t>这种便利接口。
