如何从IoC容器返回正确的类?C#命令映射场景技术问询
嘿,看起来你已经把命令模式的核心组件(命令、调度器、工厂)都搭好了,现在想要做一个统一的容器来管理它们的映射关系,还支持一个调度器工厂处理多个命令的场景对吧?我来给你分享一个实用的实现方案,完全贴合你的需求。
首先我先基于你的描述补全一下基础接口的假设(毕竟你没贴全,这样后面的容器实现更有上下文):
// 基础命令接口,所有命令都要实现它 public interface ICommand { // 可选:如果需要用字符串标识命令,也可以加这个属性 // string CommandId { get; } } // 调度器接口,负责执行具体命令逻辑 public interface IScheduler { void Dispatch(ICommand command); } // 调度器工厂接口,用来创建调度器实例(支持依赖注入等场景) public interface ISchedulerFactory { IScheduler CreateScheduler(); }
命令容器的设计与实现
1. 定义容器接口
先把容器的核心能力抽象成接口,方便后续扩展或者替换实现:
public interface ICommandContainer { // 注册单个命令类型到对应的调度器工厂 void Register<TCommand>(ISchedulerFactory factory) where TCommand : ICommand; // 批量注册多个命令到同一个工厂(满足你说的分组处理需求) void RegisterMultiple(IEnumerable<Type> commandTypes, ISchedulerFactory factory); // 封装的调度入口,外部只需要传入命令,容器自动找对应工厂执行 void Dispatch(ICommand command); }
2. 容器的具体实现
用字典存储命令类型和工厂的映射,逻辑清晰且性能高效:
public class CommandContainer : ICommandContainer { // 核心映射表:命令Type -> 对应的调度器工厂 private readonly Dictionary<Type, ISchedulerFactory> _commandFactoryMap = new(); public void Register<TCommand>(ISchedulerFactory factory) where TCommand : ICommand { var commandType = typeof(TCommand); if (_commandFactoryMap.ContainsKey(commandType)) { // 这里可以根据业务需求选择覆盖、抛异常或者打日志 throw new InvalidOperationException($"命令类型 {commandType.Name} 已经被注册过了"); } _commandFactoryMap[commandType] = factory; } public void RegisterMultiple(IEnumerable<Type> commandTypes, ISchedulerFactory factory) { foreach (var commandType in commandTypes) { // 先校验是否是ICommand的实现类 if (!typeof(ICommand).IsAssignableFrom(commandType)) { throw new ArgumentException($"类型 {commandType.Name} 没有实现ICommand接口"); } if (_commandFactoryMap.ContainsKey(commandType)) { throw new InvalidOperationException($"命令类型 {commandType.Name} 已经被注册过了"); } _commandFactoryMap[commandType] = factory; } } public void Dispatch(ICommand command) { var commandType = command.GetType(); if (!_commandFactoryMap.TryGetValue(commandType, out var factory)) { throw new InvalidOperationException($"没有为命令类型 {commandType.Name} 注册对应的调度器工厂"); } // 创建调度器并执行命令 var scheduler = factory.CreateScheduler(); scheduler.Dispatch(command); } }
3. 使用示例(完全贴合你的分组需求)
比如你提到的CommandBackupAndDeleteFile,还有同组的备份、删除命令,都可以映射到同一个工厂:
// 示例命令 public class CommandBackupFile : ICommand { } public class CommandDeleteFile : ICommand { } public class CommandBackupAndDeleteFile : ICommand { } // 处理这一组命令的调度器 public class FileOperationScheduler : IScheduler { public void Dispatch(ICommand command) { // 根据命令类型执行不同逻辑 switch (command) { case CommandBackupFile _: Console.WriteLine("执行文件备份逻辑"); break; case CommandDeleteFile _: Console.WriteLine("执行文件删除逻辑"); break; case CommandBackupAndDeleteFile _: Console.WriteLine("先备份文件,再删除原文件"); break; default: throw new ArgumentException("不支持的文件操作命令"); } } } // 对应的工厂 public class FileOperationSchedulerFactory : ISchedulerFactory { public IScheduler CreateScheduler() { // 这里可以注入依赖(比如日志、文件服务等) return new FileOperationScheduler(); } } // 另一个独立命令示例 public class CommandCleanCache : ICommand { } public class CleanCacheScheduler : IScheduler { public void Dispatch(ICommand command) => Console.WriteLine("清理系统缓存"); } public class CleanCacheSchedulerFactory : ISchedulerFactory { public IScheduler CreateScheduler() => new CleanCacheScheduler(); }
然后注册和使用容器:
// 初始化容器 var commandContainer = new CommandContainer(); // 批量注册文件操作组的命令到同一个工厂 var fileCommandTypes = new[] { typeof(CommandBackupFile), typeof(CommandDeleteFile), typeof(CommandBackupAndDeleteFile) }; commandContainer.RegisterMultiple(fileCommandTypes, new FileOperationSchedulerFactory()); // 注册单个缓存清理命令 commandContainer.Register<CommandCleanCache>(new CleanCacheSchedulerFactory()); // 执行命令,外部完全不用关心调度器细节 commandContainer.Dispatch(new CommandBackupAndDeleteFile()); // 输出:先备份文件,再删除原文件 commandContainer.Dispatch(new CommandCleanCache()); // 输出:清理系统缓存
4. 可选优化建议
- 集成依赖注入:如果你的项目用了DI框架(比如微软的DI、Autofac),可以把
CommandContainer和所有工厂注册到DI容器中,工厂创建调度器时自动注入依赖,不用手动new。 - 灵活的命令标识:如果不想用
Type作为映射键,也可以用命令的唯一字符串标识(比如ICommand加个CommandId属性),这样更适合动态配置的场景。 - 容错处理:可以把抛出异常改成返回
bool或者自定义结果对象,结合日志记录,避免程序因为未注册命令直接崩溃。 - 单例调度器:如果调度器是无状态的,可以让工厂返回单例实例,减少对象创建的开销。
内容的提问来源于stack exchange,提问作者Laevus
相关产品推荐
相关产品推荐

