共计 1808 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点
开发 C# 控制台应用时,最头疼的就是处理命令行参数。每次都要写一堆 if-else 来判断用户输入了什么命令,然后手动解析参数。比如这样:

if (args[0] == "add-user")
{var name = args[1];
var age = int.Parse(args[2]);
AddUser(name, age);
}
else if (args[0] == "delete-user")
{// 又一套参数解析...}
这种写法有三大问题:
- 重复劳动:每个命令都要写解析逻辑
- 难以维护:命令多了后 if-else 链会非常长
- 缺乏自描述:没有内置帮助文档生成
技术方案
我们采用反射 + 特性标注的方案,主要思路是:
- 用
[Command]标记命令方法 - 自动将命令行参数绑定到方法参数
- 运行时动态发现所有命令
相比 System.CommandLine 官方库,我们的方案更轻量,适合需要快速集成的小型项目。
核心实现
1. 定义命令特性
[AttributeUsage(AttributeTargets.Method)]
public class CommandAttribute : Attribute
{public string Name { get;}
public string HelpText {get; set;}
public CommandAttribute(string name)
{Name = name;}
}
2. 命令执行器核心
public class CommandExecutor
{
private readonly Dictionary<string, MethodInfo> _commands;
public CommandExecutor()
{_commands = Assembly.GetExecutingAssembly()
.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => m.GetCustomAttribute<CommandAttribute>() != null)
.ToDictionary(m => m.GetCustomAttribute<CommandAttribute>()!.Name,
m => m);
}
public async Task ExecuteAsync(string[] args)
{if (args.Length == 0 || !_commands.TryGetValue(args[0], out var method))
{ShowHelp();
return;
}
try
{var parameters = BuildParameters(method, args.Skip(1).ToArray());
var result = method.Invoke(null, parameters);
if (result is Task task)
{await task;}
}
catch (Exception ex)
{Console.WriteLine($"Error: {ex.Message}");
}
}
private object?[] BuildParameters(MethodInfo method, string[] args)
{// 参数绑定逻辑...}
}
进阶优化
1. 使用 Source Generator
反射虽然方便,但会影响启动性能。可以用 Source Generator 在编译时生成命令路由表:
[Command("add-user")]
public static void AddUser(string name, int age)
{// 业务逻辑}
编译器会为这个命令自动生成注册代码。
2. 异步支持
处理异步命令时需要特别注意:
- 检查方法返回类型是否是
Task - 使用
await等待异步操作完成 - 异常处理要同时捕获同步和异步异常
避坑指南
- 文化差异问题:
DateTime.Parse会受到系统区域设置影响-
建议使用
CultureInfo.InvariantCulture -
反射性能:
- 缓存 MethodInfo 对象
-
避免每次调用都重新查找方法
-
单元测试:
- 用
StringWriter重定向 Console.Out - 模拟 Console.In 输入测试数据
开放性问题
- 如何将命令系统集成到 ASP.NET Core 的 DI 容器?
- 是否支持子命令嵌套(如
git remote add)? - 如何实现命令的权限控制系统?
这套方案我们已经在实际项目中验证,将命令行工具的开发效率提升了 50% 以上。核心思想是通过约定优于配置,让开发者聚焦业务逻辑而不是参数解析。
正文完
