最简方案是直接读取args数组,但仅适用于无空格、无引号、无等号赋值的基础场景;真正可靠应使用System.CommandLine(.NET 6+官方推荐)或CommandLineParser(兼容旧框架),并需将命令行参数作为配置源集成到IConfiguration中。

直接读 args 数组是最简方案,但仅适用于最基础场景
绝大多数 C# 控制台程序启动时,Main(string[] args) 的 args 就是原始命令行参数字符串数组,空格分隔、无解析、不处理引号或转义。比如运行 myapp.exe -f config.json --verbose,args 会是 ["-f", "config.json", "--verbose"] —— 看似合理,但一旦参数含空格(如 "C:\My Folder\file.txt")或等号(--output=report.csv),原生 args 就会切错。
所以别指望靠手动 Split(' ') 或遍历下标来“凑合用”,Windows 和 .NET 对命令行的预处理已经完成,args 是最终结果,不是原始字符串。
- Windows 下双引号内的空格会被保留在同一
args元素里,Linux/macOS 也类似,但行为依赖 shell -
args不区分长选项/短选项,-h和--help都只是普通字符串 - 没有默认值、类型转换、帮助生成、错误提示等能力
用 System.CommandLine 解析才真正可靠
.NET 6+ 官方推荐的命令行库,比手写 switch 判断更健壮,也比旧版 CommandLineParser 更现代。它能自动处理引号、等号赋值、布尔开关、子命令、类型绑定(比如把 "42" 转成 int)。
安装包:dotnet add package System.CommandLine
- 核心是定义
RootCommand+Option+Argument,而非解析args字符串 - 支持
--port 8080和--port=8080两种写法 - 遇到未知选项或类型错误时,默认抛出
ParseException,可捕获并输出友好提示 - 内置
--help输出,字段注释会自动变成帮助文本
示例:定义一个接收文件路径和是否静默的命令
var root = new RootCommand("My tool");
var fileOpt = new Option<string>("--file", "Input file path");
var quietOpt = new Option<bool>("--quiet", "Suppress output");
root.AddOption(fileOpt);
root.AddOption(quietOpt);
root.SetHandler((file, quiet) =>
{
Console.WriteLine($"File: {file}, Quiet: {quiet}");
}, fileOpt, quietOpt);
await root.InvokeAsync(args);如果必须兼容 .NET Framework 或极简项目,CommandLineParser 是折中选择
这个老牌库(nuget 包名 CommandLineParser)仍被大量老项目使用,语法简洁,无额外运行时依赖,但已停止维护(最后更新 2021)。它用属性标记类字段,再调用 Parser.Default.ParseArguments 绑定。
- 必须为每个参数建一个
class,字段加[Option]或[Value]特性 - 不支持子命令,复杂 CLI 结构会写得很臃肿
- 对中文路径、Unicode 参数支持尚可,但等号赋值(
--log=info)需显式启用EnableDashDash - 错误信息较原始,比如
"Required option '--file' is missing.",不如System.CommandLine可定制
示例结构:
class Options
{
[Option('f', "file", Required = true)]
public string File { get; set; }
<pre class="brush:php;toolbar:false;">[Option("quiet")]
public bool Quiet { get; set; }}
// ...
Parser.Default.ParseArguments
容易被忽略的坑:环境变量和配置文件优先级比命令行还高?
实际项目中,命令行参数往往不是唯一配置来源。用户常误以为“命令行输的就一定生效”,但真实逻辑通常是:环境变量 → 配置文件 → 命令行参数(后者覆盖前者)。比如 ASPNETCORE_ENVIRONMENT 会影响整个 Host 行为,而 System.CommandLine 默认不介入这个层级。
- 不要在
Program.cs顶层直接解析args后就初始化服务,应先构建IConfiguration,把args作为CommandLineConfigurationProvider注入 - 第三方库(如 Serilog、EF Core)通常只认
IConfiguration,不认裸args - 调试时在 IDE 里改“启动参数”可能和终端运行行为不一致,特别是引号嵌套和反斜杠转义
真正要让命令行参数参与整个应用生命周期,得把它变成配置源的一部分,而不是单独拎出来处理一次就完事。










