You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:53:31