C#常用类库YamlDotNet详解
作者:阿蒙Armon
在C#开发中,数据序列化与反序列化是高频需求,广泛应用于配置文件、数据传输、日志存储等场景。YAML作为简洁易读的非标记语言,相比XML繁琐、JSON紧凑的特点,更适合作为配置文件和高可读性的数据交换格式。而YamlDotNet作为C#生态最主流的YAML处理类库,开源免费、功能强大,是处理YAML数据的首选工具。本文聚焦实战,从核心定位、环境搭建、基础用法到进阶技巧,帮你快速掌握YamlDotNet全流程用法。
一、YamlDotNet 核心定位与优势
YamlDotNet是基于MIT许可证的开源C#类库,核心功能是实现.NET对象与YAML格式的双向转换(序列化/反序列化),底层封装了YAML语法解析器与生成器,提供简洁API,支持自定义规则,适配复杂业务场景。
1. 核心优势
- 开源免费:可自由用于商业项目,源码可定制,社区活跃,适配.NET全框架(.NET Framework 4.5+、.NET Core 2.0+、.NET 5+)。
- 功能完整:支持基本类型、自定义类、集合、泛型、继承类的序列化/反序列化,兼容YAML 1.1和1.2规范。
- 灵活可扩展:支持自定义序列化规则、属性映射、忽略指定属性、保留注释,适配复杂业务场景。
- 兼容性强:跨平台支持(Windows、Linux、macOS),无第三方依赖,集成简单。
- 性能优异:解析速度快、内存占用低,支持大数据量YAML文档处理,满足企业级需求。
2. 与其他序列化类库选型对比
| 类库 | 核心优势 | 不足 | 选型建议 |
|---|---|---|---|
| YamlDotNet | 专注YAML,易用性强、扩展灵活,支持注释和复杂类型 | 序列化速度略逊于Newtonsoft.Json,不支持JSON | 配置文件、高可读性数据交换首选 |
| Newtonsoft.Json | 速度快、功能丰富、生态完善,专注JSON | 不支持YAML,配置文件可读性差 | JSON数据传输、接口交互场景 |
| System.Xml.Serialization | 内置无依赖,适配传统XML配置 | 语法繁琐、扩展性低,不支持YAML | 旧项目XML配置兼容场景 |
| SharpYaml | 轻量、解析快,支持YAML 1.2 | 社区活跃低、高级功能不完善 | 简单YAML解析场景,不推荐复杂项目 |
3. 核心应用场景
- 配置文件:替代XML、JSON,作为appsettings.yaml等配置文件,便于人工编辑。
- 数据交换:微服务、跨语言项目中,作为高可读性的数据交换格式。
- 日志存储:将复杂日志对象序列化为YAML,便于分析查看。
- 文档生成:生成YAML格式接口文档、K8s配置文件等。
- 数据导入导出:实现系统数据的备份与恢复。
二、环境搭建:快速集成YamlDotNet
YamlDotNet为第三方类库,需通过NuGet安装,搭建流程简单,适配所有.NET版本。
1. 安装方式(3种任选)
方式1:NuGet界面安装
Visual Studio → 右键项目 → 管理NuGet程序包 → 搜索“YamlDotNet” → 安装最新稳定版。
方式2:Package Manager Console命令
Install-Package YamlDotNet -Version 13.7.1 # 可替换为最新版本
方式3:手动修改.csproj文件
<ItemGroup> <PackageReference Include="YamlDotNet" Version="13.7.1" /> </ItemGroup>
2. 引入命名空间
using YamlDotNet; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions;
3. 环境验证
编写简单代码,验证序列化与反序列化功能是否正常:
// 1. 定义测试类
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; }
}
// 2. 序列化(对象→YAML)
var user = new User { Name = "ZhangSan", Age = 25, Hobbies = new List<string> { "Coding", "Reading" } };
var serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();
string yaml = serializer.Serialize(user);
Console.WriteLine("序列化结果:\n" + yaml);
// 3. 反序列化(YAML→对象)
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
User deserializedUser = deserializer.Deserialize<User>(yaml);
Console.WriteLine($"反序列化结果:Name={deserializedUser.Name}, Age={deserializedUser.Age}");运行程序,正常输出结果即说明环境搭建成功。
三、基础实战:核心用法(序列化+反序列化)
YamlDotNet的核心的是序列化与反序列化,以下覆盖常用场景,代码可直接复制使用。
1. 通用配置
序列化器与反序列化器的常用配置,统一配置可提升代码复用性:
// 序列化器配置
var serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance) // 驼峰命名
.Indent(2) // 缩进2个空格
.WithCommentHandling(CommentHandling.IncludeComments) // 保留注释
.Build();
// 反序列化器配置
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties() // 忽略未知属性,避免报错
.AllowNullValues() // 允许空值
.Build();2. 基本类型与集合
支持string、int、DateTime等基本类型,以及List、Dictionary等集合:
var data = new
{
Name = "LiSi",
Age = 30,
BirthDate = new DateTime(1993, 10, 1),
Tags = new string[] { "C#", "YamlDotNet" },
Scores = new Dictionary<string, int> { { "Math", 90 }, { "English", 85 } }
};
// 序列化
string yaml = serializer.Serialize(data);
// 反序列化(dynamic类型,无需定义实体类)
dynamic deserialized = deserializer.Deserialize<dynamic>(yaml);
Console.WriteLine($"Math Score: {deserialized.scores.math}");3. 自定义类(重点)
支持自定义类、继承类、嵌套类的序列化与反序列化:
// 嵌套类
public class Address { public string Province { get; set; } public string City { get; set; } }
// 父类
public class Person { public string Name { get; set; } public int Age { get; set; } }
// 子类
public class Student : Person
{
public string StudentId { get; set; }
public Address Address { get; set; }
public List<string> Courses { get; set; }
}
// 序列化
var student = new Student
{
Name = "WangWu",
Age = 20,
StudentId = "2023001",
Address = new Address { Province = "Guangdong", City = "Shenzhen" },
Courses = new List<string> { "C#", "Database" }
};
string studentYaml = serializer.Serialize(student);
// 反序列化
Student deserializedStudent = deserializer.Deserialize<Student>(studentYaml);4. 特性用法(自定义规则)
通过特性自定义单个属性的序列化规则,灵活适配需求:
using YamlDotNet.Serialization.Attributes;
public class Product
{
[YamlAlias("product_id")] // 别名,YAML中显示为product_id
public string Id { get; set; }
[YamlIgnore] // 忽略该属性,不序列化/反序列化
public string Secret { get; set; }
[YamlComment("产品名称(必填)")] // 添加注释
public string Name { get; set; }
[YamlMember(Order = 1)] // 指定序列化顺序
public decimal Price { get; set; }
}四、进阶实战:企业级优化技巧
基础用法可满足简单场景,企业级项目需解决复杂类型、性能、稳定性等问题,以下是核心技巧。
1. 自定义类型转换器
针对DateTime、Enum等复杂类型,自定义转换规则(以DateTime格式化为例):
// 实现自定义转换器
public class CustomDateTimeConverter : IYamlTypeConverter
{
public bool Accepts(Type type) => type == typeof(DateTime) || type == typeof(DateTime?);
// 反序列化:字符串→DateTime
public object ReadYaml(IParser parser, Type type)
{
var value = parser.Consume<Scalar>().Value;
return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:ss", null);
}
// 序列化:DateTime→字符串
public void WriteYaml(IEmitter emitter, object value, Type type)
{
emitter.Emit(new Scalar(((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss")));
}
}
// 注册并使用
var serializer = new SerializerBuilder()
.WithTypeConverter(new CustomDateTimeConverter())
.Build();2. YAML文件读写(实战常用)
封装工具方法,实现对象与YAML文件的双向读写:
/// <summary>
/// 序列化对象到YAML文件
/// </summary>
public void SerializeToFile(object obj, string filePath)
{
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
serializer.Serialize(writer, obj);
}
}
/// <summary>
/// 从YAML文件反序列化到对象
/// </summary>
public T DeserializeFromFile<T>(string filePath)
{
if (!File.Exists(filePath)) throw new FileNotFoundException("YAML文件不存在", filePath);
using (var reader = new StreamReader(filePath, Encoding.UTF8))
{
return deserializer.Deserialize<T>(reader);
}
}3. 异常处理与性能优化
(1)异常处理
完善异常处理,避免程序崩溃,提升稳定性:
public T DeserializeWithExceptionHandling<T>(string yaml)
{
try
{
return deserializer.Deserialize<T>(yaml);
}
catch (YamlException ex)
{
Console.WriteLine($"YAML语法错误:{ex.Message},行号:{ex.Start.Line}");
return default;
}
catch (InvalidCastException ex)
{
Console.WriteLine($"类型转换错误:{ex.Message}");
return default;
}
catch (Exception ex)
{
Console.WriteLine($"反序列化失败:{ex.Message}");
return default;
}
}(2)性能优化(大数据量场景)
- 使用Stream读写,减少内存占用;
- 复用序列化器/反序列化器实例(单例模式);
- 禁用不必要的功能(如注释处理);
- 避免使用dynamic类型,优先使用具体类型。
五、避坑指南与最佳实践
1. 常见坑与解决方案
- 坑1:YAML语法错误:缩进用空格(不支持Tab),冒号、横杠后必须加空格;用在线工具校验语法。
- 坑2:命名不一致:序列化与反序列化配置相同的命名约定,或用[YamlAlias]指定别名。
- 坑3:复杂类型格式不符:实现自定义类型转换器,或使用内置配置。
- 坑4:未知属性报错:配置IgnoreUnmatchedProperties()忽略未知属性。
- 坑5:大数据量性能差:用Stream、复用实例、禁用注释处理。
2. 最佳实践
- 统一命名约定,保持序列化与反序列化配置一致;
- 复用序列化器/反序列化器实例,提升性能;
- 敏感字段用[YamlIgnore]忽略,关键属性加注释;
- 配置文件场景保留注释,便于维护;
- 序列化后校验YAML语法,避免反序列化失败。
六、企业级实战案例:配置文件读写工具
结合前文知识点,实现可直接复用的YAML配置读写工具,适配项目全局配置场景。
1. 项目结构
YamlConfigDemo/ ├─ Config/ │ ├─ AppConfig.cs(配置实体) │ └─ YamlConfigHelper.cs(工具类) ├─ appsettings.yaml(配置文件) └─ Program.cs(测试入口)
2. 核心代码
(1)配置实体类(AppConfig.cs)
using YamlDotNet.Serialization.Attributes;
namespace YamlConfigDemo.Config
{
public class AppConfig
{
[YamlComment("应用名称(必填)")]
public string AppName { get; set; }
[YamlComment("应用版本")]
public string Version { get; set; }
[YamlComment("数据库配置")]
public DatabaseConfig Database { get; set; }
[YamlComment("服务配置")]
public ServiceConfig Service { get; set; }
}
public class DatabaseConfig
{
[YamlAlias("connection_string")]
public string ConnectionString { get; set; }
[YamlAlias("timeout")]
public int Timeout { get; set; } = 30;
}
public class ServiceConfig
{
[YamlAlias("base_url")]
public string BaseUrl { get; set; }
[YamlAlias("timeout")]
public int Timeout { get; set; } = 5000;
}
}(2)配置读写工具类(YamlConfigHelper.cs)
using System.IO;
using System.Text;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace YamlConfigDemo.Config
{
public static class YamlConfigHelper
{
// 单例复用实例
private static readonly Serializer _serializer;
private static readonly Deserializer _deserializer;
static YamlConfigHelper()
{
_serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.WithCommentHandling(CommentHandling.IncludeComments)
.Indent(4)
.Build();
_deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.AllowNullValues()
.Build();
}
// 读取配置
public static T ReadConfig<T>(string filePath)
{
if (!File.Exists(filePath)) throw new FileNotFoundException("配置文件不存在", filePath);
using (var reader = new StreamReader(filePath, Encoding.UTF8))
{
return _deserializer.Deserialize<T>(reader);
}
}
// 写入配置
public static void WriteConfig(object config, string filePath)
{
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
_serializer.Serialize(writer, config);
}
}
}
}(3)测试使用(Program.cs)
using YamlConfigDemo.Config;
// 写入配置
var config = new AppConfig
{
AppName = "YamlDotNetDemo",
Version = "1.0.0",
Database = new DatabaseConfig
{
ConnectionString = "Server=localhost;Database=Test;Uid=root;Pwd=123456;"
},
Service = new ServiceConfig
{
BaseUrl = "https://api.demo.com"
}
};
YamlConfigHelper.WriteConfig(config, "appsettings.yaml");
// 读取配置
var readConfig = YamlConfigHelper.ReadConfig<AppConfig>("appsettings.yaml");
Console.WriteLine($"应用名称:{readConfig.AppName}");
Console.WriteLine($"数据库连接串:{readConfig.Database.ConnectionString}");总结
YamlDotNet是C#处理YAML数据的最优选择,其易用性、灵活性和兼容性,能完美适配配置文件、数据交换等各类场景。本文从基础到进阶,覆盖环境搭建、核心用法、优化技巧和实战案例,代码可直接复用。掌握本文内容,可轻松解决YAML序列化/反序列化的各类问题,提升开发效率。
到此这篇关于C#常用类库YamlDotNet详解的文章就介绍到这了,更多相关C#常用类库YamlDotNet内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
