共计 2005 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
开发 C# 控制台应用时,手动解析命令行参数是个常见但繁琐的任务。每次都要写一堆 if-else 判断参数,不仅代码冗长,还容易出错。更糟的是,随着功能增加,代码会变得越来越难以维护。

- 传统方式需要手动解析
args数组,处理各种参数组合 - 命令和参数验证逻辑散落在代码各处,难以统一管理
- 添加新命令时,需要修改主逻辑,违反了开闭原则
技术方案
为了解决这些问题,我们设计了一个基于反射和特性标注的模块化方案。核心思路是:
- 使用
[Command]特性标记可执行的方法 - 通过反射自动发现这些命令方法
- 利用 ParameterInfo 实现类型安全的参数绑定
与 System.CommandLine 相比,这个方案更轻量,更适合需要高度自定义的场景。
核心实现
CommandExecutor 类设计
public class CommandExecutor
{
private readonly Dictionary<string, MethodInfo> _commandCache;
public CommandExecutor()
{_commandCache = new Dictionary<string, MethodInfo>(StringComparer.OrdinalIgnoreCase);
}
public void RegisterCommands(Assembly assembly)
{foreach (var type in assembly.GetTypes())
{foreach (var method in type.GetMethods())
{var attr = method.GetCustomAttribute<CommandAttribute>();
if (attr != null)
{_commandCache[attr.Name ?? method.Name] = method;
}
}
}
}
public async Task ExecuteAsync(string commandName, string[] args)
{if (!_commandCache.TryGetValue(commandName, out var method))
throw new CommandNotFoundException(commandName);
// 参数解析和类型转换逻辑...
}
}
命令特性定义
[AttributeUsage(AttributeTargets.Method)]
public class CommandAttribute : Attribute
{public string Name { get;}
public string Description {get; set;}
public CommandAttribute(string name = null)
{Name = name;}
}
错误处理机制
我们定义了自定义异常类来处理各种错误情况:
public class CommandException : Exception
{public CommandException(string message) : base(message) {}}
public class CommandNotFoundException : CommandException
{public CommandNotFoundException(string commandName)
: base($"Command'{commandName}'not found") {}}
进阶优化
使用 Source Generator
为了避免运行时反射的性能开销,可以使用 Source Generator 在编译时生成命令路由表:
[Generator]
public class CommandSourceGenerator : ISourceGenerator
{public void Initialize(GeneratorInitializationContext context) { }
public void Execute(GeneratorExecutionContext context)
{// 扫描程序集中的 Command 方法并生成路由代码}
}
异步命令处理
处理异步命令时需要注意:
- 确保 CommandExecutor 本身是线程安全的
- 正确 await 异步方法调用
- 处理好取消令牌的传递
避坑指南
文化敏感参数
处理 DateTime 等文化敏感类型时,建议:
- 明确指定文化设置
- 提供统一的解析方法
- 在帮助文档中注明格式要求
反射性能优化
- 缓存 MethodInfo 等反射结果
- 避免在热路径上进行反射操作
- 考虑使用表达式树编译委托
单元测试要点
测试命令行应用时要注意:
- 模拟 Console.In/Out 进行输入输出测试
- 测试各种参数组合和边界条件
- 验证错误消息的准确性
总结与展望
这套方案显著提升了控制台应用的开发效率,使代码更模块化、更易维护。未来可以考虑:
- 如何与 DI 容器集成
- 支持更复杂的参数验证规则
- 添加自动补全功能
你对这个方案有什么想法?欢迎在评论区分享你的见解!
正文完
