TOML 文件在 C# 中的全面指南
适用于 .NET 开发者:从基础概念到实战应用,掌握现代配置文件格式 TOML 在 C# 项目中的使用方法。
一、什么是 TOML?
TOML(Tom’s Obvious, Minimal Language)是一种语义明确、易于阅读和编写的配置文件格式,由 GitHub 联合创始人 Tom Preston-Werner 提出。其设计目标是成为比 JSON、YAML、INI 更直观、无歧义的配置语言。
核心特点
- ✅ 人类可读:语法简洁,结构清晰
- ✅ 强类型支持:原生支持字符串、整数、布尔、日期、数组、嵌套表等
- ✅ 标准化:有明确规范(toml.io),跨语言兼容
- ✅ 支持注释:使用
# 添加说明
- ✅ 层级结构:通过
[section] 和 [section.subsection] 实现嵌套
示例 TOML 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 应用基本信息
title = "My C# Application"
version = "1.0.0"
[server]
host = "localhost"
port = 8080
ssl_enabled = true
[database]
server = "192.168.1.10"
port = 5432
[database.credentials]
username = "admin"
password = "s3cr3t"
|
二、TOML 与其他配置格式对比
| 特性 |
TOML |
INI |
JSON |
YAML |
| 人类可读性 |
⭐⭐⭐⭐ |
⭐⭐⭐ |
⭐⭐ |
⭐⭐⭐⭐ |
| 支持注释 |
✅(#) |
✅(# 或 ;,不标准) |
❌ |
✅(#) |
| 数据类型 |
原生支持多种类型 |
仅字符串 |
支持基本类型 |
支持但易出错 |
| 嵌套结构 |
✅(通过表) |
❌(需命名约定) |
✅(对象) |
✅(缩进) |
| 标准规范 |
✅(严格) |
❌(各实现不一) |
✅ |
✅(但复杂) |
| 缩进敏感 |
❌ |
❌ |
❌ |
✅(易错) |
| 适合手写 |
✅✅✅ |
✅✅ |
❌ |
✅(但需小心缩进) |
💡 结论:TOML 是 INI 的现代化升级版,兼具可读性与结构表达能力,特别适合应用程序配置文件。
三、为什么在 C# 项目中使用 TOML?
- 现代项目趋势:Rust(
Cargo.toml)、Python(pyproject.toml)、Deno 等广泛采用
- 优于传统
appsettings.json:支持注释,结构更清晰,避免 JSON 的“无注释”痛点
- 比 XML 简洁:无需闭合标签,无命名空间复杂性
- 比 YAML 安全:无缩进陷阱,无类型自动推断风险
📌 典型应用场景:
- 应用程序主配置文件(替代
appsettings.json)
- 插件/模块配置
- 构建脚本参数(如自定义构建工具)
- 游戏或桌面应用的用户设置
四、C# 中读写 TOML:使用 Tomlyn 库
.NET 官方未内置 TOML 支持,但社区库 Tomlyn 是目前最成熟、轻量、高性能的选择。
1. 安装
通过 NuGet 安装:
1
|
dotnet add package Tomlyn
|
或在 .csproj 中添加:
1
|
<PackageReference Include="Tomlyn" Version="0.15.0" />
|
✅ 支持 .NET Standard 2.0+,兼容 .NET Core、.NET 5/6/7/8 及 .NET Framework。
2. 加载 TOML 文件
方式一:强类型反序列化(推荐)
适用于结构固定的配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
using Tomlyn;
public class AppConfig
{
public string Title { get; set; } = "";
public ServerConfig Server { get; set; } = new();
public DatabaseConfig Database { get; set; } = new();
}
public class ServerConfig
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 8080;
public bool SslEnabled { get; set; }
}
public class DatabaseConfig
{
public string Server { get; set; } = "";
public int Port { get; set; }
public DbCredentials Credentials { get; set; } = new();
}
public class DbCredentials
{
public string Username { get; set; } = "";
public string Password { get; set; } = "";
}
|
加载代码:
1
2
3
4
|
string toml = File.ReadAllText("app.toml");
var config = Toml.ToModel<AppConfig>(toml);
Console.WriteLine($"Server: {config.Server.Host}:{config.Server.Port}");
|
✅ 自动类型转换:int、bool、嵌套对象等无需手动解析。
方式二:动态解析(灵活但需手动处理)
适用于结构未知或临时解析。
1
2
3
4
5
6
|
using Tomlyn.Model;
var model = Toml.ToModel(File.ReadAllText("config.toml"));
var server = (TomlTable)model["server"];
string host = (string)server["host"];
int port = (int)server["port"];
|
⚠️ 注意:需显式类型转换,嵌套需递归处理。
3. 保存 TOML 文件
将 C# 对象序列化为 TOML 文本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var config = new AppConfig
{
Title = "My App",
Server = new() { Host = "0.0.0.0", Port = 9000, SslEnabled = false },
Database = new()
{
Server = "db.example.com",
Port = 5432,
Credentials = new() { Username = "user", Password = "pass" }
}
};
string tomlText = Toml.FromModel(config);
File.WriteAllText("app.toml", tomlText);
|
输出示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
title = "My App"
[server]
host = "0.0.0.0"
port = 9000
ssl_enabled = false
[database]
server = "db.example.com"
port = 5432
[database.credentials]
username = "user"
password = "pass"
|
4. 高级特性
自定义字段名映射
当 TOML 键名与 C# 属性名不一致时,使用 [TomlProperty]:
1
2
3
4
5
6
7
8
|
public class ServerConfig
{
[TomlProperty("bind_address")]
public string Host { get; set; } = "";
[TomlProperty("use_tls")]
public bool SslEnabled { get; set; }
}
|
对应 TOML:
1
2
3
|
[server]
bind_address = "127.0.0.1"
use_tls = true
|
数组支持
TOML:
1
2
|
allowed_ips = ["192.168.1.1", "10.0.0.5"]
ports = [8080, 8081, 8082]
|
C#:
1
2
|
public List<string> AllowedIps { get; set; } = new();
public int[] Ports { get; set; } = Array.Empty<int>();
|
日期时间
TOML 支持 RFC 3339 日期:
1
|
created_at = 2025-10-30T14:30:00Z
|
C#:
1
|
public DateTime CreatedAt { get; set; }
|
五、完整工具类封装(推荐复用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
using Tomlyn;
using System.IO;
/// <summary>
/// TOML 配置文件读写工具类
/// </summary>
public static class TomlConfigHelper
{
/// <summary>
/// 从文件加载 TOML 配置(强类型)
/// </summary>
public static T Load<T>(string filePath) where T : new()
{
if (!File.Exists(filePath))
throw new FileNotFoundException($"TOML 配置文件不存在: {filePath}");
var content = File.ReadAllText(filePath);
return Toml.ToModel<T>(content);
}
/// <summary>
/// 保存配置对象到 TOML 文件
/// </summary>
public static void Save<T>(string filePath, T config)
{
var content = Toml.FromModel(config);
Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? ".");
File.WriteAllText(filePath, content);
}
}
|
使用示例:
1
2
3
4
5
6
7
8
9
|
// 首次运行:创建默认配置
if (!File.Exists("config.toml"))
{
var defaultConfig = new AppConfig { Title = "My App" };
TomlConfigHelper.Save("config.toml", defaultConfig);
}
// 加载配置
var config = TomlConfigHelper.Load<AppConfig>("config.toml");
|
六、常见问题与注意事项
| 问题 |
解决方案 |
| 属性未赋值 |
确保属性为 public 且有 set 访问器 |
| 类型转换异常 |
检查 TOML 值类型是否匹配(如 "8080" 是字符串,应写为 8080) |
| 嵌套结构不匹配 |
C# 类的嵌套层级必须与 TOML 表结构一致 |
| 中文乱码 |
保存 TOML 文件时使用 UTF-8 编码(File.WriteAllText 默认 UTF-8) |
| 注释丢失 |
Tomlyn 不保留注释(符合 TOML 规范),如需保留注释需用其他方案 |
⚠️ TOML 规范要求:键名区分大小写,字符串建议用双引号(虽然部分值可无引号,但为安全起见推荐显式使用)。
七、与其他 .NET 配置系统的集成(可选)
虽然 TOML 不能直接用于 Microsoft.Extensions.Configuration(如 ASP.NET Core 的 IConfiguration),但可通过自定义 ConfigurationProvider 实现集成。
🔧 如有需要,可基于 Tomlyn 实现 TomlConfigurationProvider,将 TOML 文件纳入标准配置管道。
八、总结
| 优势 |
说明 |
| 简洁直观 |
比 JSON 更易读,比 YAML 更安全 |
| 类型安全 |
原生支持多种数据类型,减少解析错误 |
| 现代标准 |
被 Rust、Python 等主流生态广泛采用 |
| C# 支持完善 |
Tomlyn 库成熟、轻量、高性能 |
✅ 推荐在以下场景使用 TOML:
- 桌面应用、控制台工具、游戏等需要用户可编辑配置的项目
- 替代
appsettings.json 以支持注释和更清晰结构
- 构建系统、CI/CD 脚本中的参数配置
附录:参考资料
📝 作者建议:对于新项目,优先考虑 TOML 作为配置格式;对于现有项目,可在非核心模块中逐步引入,体验其简洁与强大。