C#中如何强制字典的Type键属于特定继承层级?
解决方案
首先先明确基础类型定义,比如先定义所有Command的基类,以及泛型约束的命令处理器基类:
// 所有Command的共同基类 public abstract class BaseCommand { } // 命令处理器的泛型基类,强制绑定继承自BaseCommand的命令 public abstract class TypeHandler<TCommand> where TCommand : BaseCommand { // 处理器核心逻辑方法示例 public abstract void Handle(TCommand command); }
直接用Dictionary<Type, TypeHandler>无法在编译阶段约束Key的类型,因此最稳妥的方式是封装一个自定义的强类型字典类,通过泛型方法实现编译时类型校验:
public class CommandHandlerDictionary { private readonly Dictionary<Type, object> _innerDict = new Dictionary<Type, object>(); // 泛型Add方法,强制约束TCommand必须继承自BaseCommand public void Add<TCommand>(TypeHandler<TCommand> handler) where TCommand : BaseCommand { var commandType = typeof(TCommand); if (_innerDict.ContainsKey(commandType)) { throw new InvalidOperationException($"已存在针对{commandType.Name}的处理器"); } _innerDict.Add(commandType, handler); } // 泛型获取方法,保证返回对应命令的处理器 public TypeHandler<TCommand> GetHandler<TCommand>() where TCommand : BaseCommand { var commandType = typeof(TCommand); if (_innerDict.TryGetValue(commandType, out var handler)) { return handler as TypeHandler<TCommand>; } throw new KeyNotFoundException($"未找到针对{commandType.Name}的处理器"); } }
使用示例
// 定义具体命令(必须继承BaseCommand) public class CreateOrderCommand : BaseCommand { public string OrderId { get; set; } } // 对应命令的处理器 public class CreateOrderHandler : TypeHandler<CreateOrderCommand> { public override void Handle(CreateOrderCommand command) { Console.WriteLine($"处理订单创建:{command.OrderId}"); } } // 初始化并使用字典 var handlerDict = new CommandHandlerDictionary(); handlerDict.Add(new CreateOrderHandler()); // 合法,符合继承约束 // 错误示例:如果命令未继承BaseCommand,编译阶段直接报错 // public class InvalidCommand { } // public class InvalidHandler : TypeHandler<InvalidCommand> { } // handlerDict.Add(new InvalidHandler()); // 编译失败,不符合泛型约束
如果不想封装自定义类,也可以通过封装添加方法做运行时校验(但仅能在运行时发现错误,不如编译时约束可靠):
var dic = new Dictionary<Type, TypeHandler>(); public void AddValidHandler<TCommand>(TypeHandler handler) where TCommand : BaseCommand { var commandType = typeof(TCommand); if (!typeof(BaseCommand).IsAssignableFrom(commandType)) { throw new ArgumentException($"类型{commandType.Name}必须继承自BaseCommand"); } dic.Add(commandType, handler); }
内容的提问来源于stack exchange,提问作者Navid_pdp11
相关产品推荐
相关产品推荐

