System.CommandLine 的核心优势是将命令行输入强类型映射为 C# 对象,支持 Option、Argument、子命令嵌套、自定义解析与验证,并通过泛型 Handler 实现零反射调用。

用 System.CommandLine 定义强类型命令行参数
System.CommandLine 的核心优势是把命令行输入直接映射为 C# 对象,避免手动拆解 args 字符串。关键不是“怎么加参数”,而是“怎么让参数自动变成你想要的类型和结构”。
比如定义一个发布命令:myapp publish --project MyApp.csproj --configuration Release --output ./bin,你可以这样建模:
- 用
Option<String></string>表示单值参数(如--project),指定别名(-p)、描述、是否必需 - 用
Option<ilist>></ilist>支持多次出现的参数(如--Property Key=Value可重复) - 用
Argument<string></string>处理位置参数(如myapp run api中的api) - 所有选项/参数都可绑定到
Handler方法的参数上,System.CommandLine 自动完成转换和验证
用 Handler 和泛型委托实现零反射调用
老式做法常依赖反射调用方法,而 System.CommandLine 推荐用强类型委托,既安全又高效。不用写 typeof(...).GetMethod(...).Invoke() 这类易错代码。
例如:
var publishCommand = new Command("publish", "Publish a .net project"); publishCommand.AddOption(projectOption); publishCommand.AddOption(configoption); publishCommand.AddOption(outputOption); <p>publishCommand.Handler = CommandHandler.Create<string, string, string>(PublishHandler);</p> <div class="aritcle_card"> <a class="aritcle_card_img" href="/ai/1319"> <img src="https://img.php.cn/upload/ai_manual/000/000/000/175680201295703.jpg" alt="AI Undetect"> </a> <div class="aritcle_card_info"> <a href="/ai/1319">AI Undetect</a> <p>让AI无法察觉,让文字更人性化,为文字体验创造无限可能。</p> <div class=""> <img src="/static/images/card_xiazai.png" alt="AI Undetect"> <span>162</span> </div> </div> <a href="/ai/1319" class="aritcle_card_btn"> <span>查看详情</span> <img src="/static/images/cardxiayige-3.png" alt="AI Undetect"> </a> </div> <p>// 方法签名完全匹配,自动注入解析后的值 static void PublishHandler(string project, string configuration, string output) { Console.WriteLine($"Publishing {project} in {configuration} to {output}"); }</p>
注意:参数名必须和 Option.Argument.GetDefaultValue() 或绑定名一致;如果想用不同名,可用 Option<t>.Alias</t> 或 Option<t>.SetName()</t> 显式对齐。
支持子命令 + 共享选项 + 配置复用
真实 CLI 工具往往有层级,比如 git commit、git push。System.CommandLine 原生支持子命令嵌套,还能让多个子命令共用一组基础选项(如 --verbose、--dry-run)。
- 用
RootCommand.AddCommand(subCmd)构建树形结构 - 共享选项不绑定到具体命令,而是添加到
RootCommand,再通过InvocationContext.ParseResult.GetValueForOption()在各 handler 中按需读取 - 也可用
Command.AddGlobalOption()(.NET 7+)自动下推到所有子命令 - 配合
ParseResult.FindResultFor()可判断某个选项是否被显式传入(区别于默认值)
自定义解析逻辑与错误处理更可控
当标准类型转换不够用(比如要解析自定义时间格式、枚举别名、文件路径存在性校验),System.CommandLine 允许你插入自己的转换器和验证器。
- 用
option.ParseArgument = result => { /* 自定义逻辑 */ }替换默认解析 - 用
option.AddValidator(opt => { if (...) return "Invalid format"; })提供友好错误提示 - 全局异常处理可通过
CommandLineBuilder.UseExceptionHandler()捕获CommandException等,并输出结构化帮助或退出码 - 错误消息不会直接抛出堆栈,而是走内置渲染器,保持 CLI 体验统一
基本上就这些。System.CommandLine 的高级用法,核心是“声明即契约”——你定义的 Option、Argument、Handler 就是用户能输入什么、程序会收到什么、出错时反馈什么。不复杂但容易忽略的是:别急着写逻辑,先花十分钟把命令结构用对象模型画清楚。