System.CommandLine 提供声明式命令行解析,自动支持选项(如 --port=8080 和 --port 8080)、参数类型转换、帮助生成、子命令嵌套及引号路径处理,避免手写易错逻辑。

直接用 System.CommandLine,别手写解析逻辑——除非你只收一个字符串且永不加选项、不改需求、不写帮助、不处理引号路径、不考虑未来子命令。
为什么不能直接遍历 args 数组
Windows 和 .NET 运行时已经完成了命令行预处理,args 是最终分割结果,不是原始字符串。它看似“够用”,但真实场景下立刻崩:
-
--port=8080和--port 8080要分别匹配,你还得防--config="C:\My App\settings.json" - 把
"42"转成int?漏掉int.TryParse或异常捕获,程序直接退出 -
myapp.exe -h要输出帮助——手写格式、对齐、缩进、换行,改一次选项就得同步改 help 文本 - 未来想加子命令(如
myapp publish --target win-x64)?重写整个解析器
System.CommandLine 的最小可用写法(.NET 6+ 直接用)
三步:定义选项 → 绑定处理器 → 执行。不需要反射、不依赖配置文件、不写 switch-case。
- 用
new Option<string>("--input")</string>定义参数,自动支持--input data.txt和--input=data.txt - 用
root.SetHandler((input, verbose) => { ... }, inputOpt, verboseOpt)绑定强类型委托,"42"传给int参数会自动报错并提示 - 调用
await root.InvokeAsync(args),-h或--help自动输出,字段注释变成帮助说明 - 别用
Environment.GetCommandLineArgs()——它第一个元素是程序路径,和Main(string[] args)的args不是一回事,混用必错
常见坑:类型、空格、短选项别名
System.CommandLine 默认不支持短选项合并(如 -abc 拆成 -a -b -c),也不自动处理带空格的布尔开关值(如 --verbose true),得手动配。
- 要支持
-v作为--verbose别名,得显式调用AddAlias("-v") - 布尔选项默认是开关式(出现即
true),如果非要--verbose true这种写法,得用new Option<bool>("--verbose")</bool>并自定义解析器 - 路径含空格(如
"C:\My Folder\conf.json")在args里已是完整字符串,但如果你定义成Argument<string></string>而非Option<string></string>,用户必须写成位置参数,容易误用 - 多个同名选项(如
--property Key1=Value1 --property Key2=Value2)要用Option<ilist>></ilist>,不是Option<string></string>
兼容旧框架(.NET Framework / .NET Core 3.1)怎么办
不能升级到 .NET 5+?System.CommandLine 不支持,硬套会编译失败。这时选 CommandLineParser 是唯一合理折中。
- NuGet 包名是
CommandLineParser,不是CommandLine——装错包编译不过 - 它用属性标记(
[Option])声明参数,比手写循环安全,但不支持子命令嵌套、无内置--help格式化、错误提示较简陋 - 不要自己抄网上“极简两百行解析器”——那些代码通常没处理
=赋值、没做类型 fallback、没覆盖 Windows 路径转义边界情况 - 如果项目已用
IConfiguration,建议把命令行作为配置源之一:Host.CreateDefaultBuilder().ConfigureAppConfiguration(...AddCommandLine(args))
最易被忽略的一点:所有现代解析库都依赖运行时对命令行的预处理结果,而这个结果在不同平台(Windows cmd / PowerShell / bash / zsh)下略有差异。测试时别只跑一遍 dotnet run -- --input test.json,还得覆盖带引号、等号、空格、中文路径的真实命令行调用。


















