如何将C#字符串关键字映射到Mediator命令或查询?
优雅替代大量if-else的MediatR动作映射方案
方案1:字典映射(策略模式简化版)
直接用字典建立action字符串到执行委托的映射,启动时一次性注册所有规则,运行时直接通过key匹配执行,性能高且易维护。
示例代码:
// 定义字典,可注入为单例服务 private readonly Dictionary<string, Func<IMediator, Task<object>>> _actionMappings; // 初始化映射(比如在构造函数或Startup中) public YourApiController(IMediator mediator) { _actionMappings = new Dictionary<string, Func<IMediator, Task<object>>> { ["GetAllOrders"] = async (mediator) => await mediator.Send(new GetAllOrdersQuery()), ["GetAllProducts"] = async (mediator) => await mediator.Send(new GetAllProductsQuery()), ["GetAllCustomers"] = async (mediator) => await mediator.Send(new GetAllCustomersQuery()) }; } // API动作方法 [HttpPost] public async Task<IActionResult> HandleAction([FromBody] dynamic payload) { string action = payload.action.ToString(); if (_actionMappings.TryGetValue(action, out var execute)) { var result = await execute(_mediator); return Ok(result); } return BadRequest($"Unsupported action: {action}"); }
优点:执行效率高,逻辑直观,调试方便;缺点:新增动作时需要手动更新字典。
方案2:特性标记+反射扫描
给每个MediatR请求类添加自定义特性,标记对应的action名称,启动时自动扫描所有请求类型并建立映射,减少手动维护成本。
第一步,定义自定义特性:
[AttributeUsage(AttributeTargets.Class)] public class ActionMappingAttribute : Attribute { public string ActionName { get; } public ActionMappingAttribute(string actionName) { ActionName = actionName; } }
第二步,给请求类标记特性:
[ActionMapping("GetAllOrders")] public class GetAllOrdersQuery : IRequest<object> { } [ActionMapping("GetAllProducts")] public class GetAllProductsQuery : IRequest<object> { }
第三步,启动时扫描并构建映射:
// 扫描程序集中所有带ActionMappingAttribute的MediatR请求类型 var requestTypes = Assembly.GetExecutingAssembly() .GetTypes() .Where(t => typeof(IRequest<object>).IsAssignableFrom(t) && t.GetCustomAttribute<ActionMappingAttribute>() != null); // 构建映射字典 _actionMappings = new Dictionary<string, Type>(); foreach (var type in requestTypes) { var attr = type.GetCustomAttribute<ActionMappingAttribute>(); _actionMappings[attr.ActionName] = type; }
第四步,API方法中执行:
[HttpPost] public async Task<IActionResult> HandleAction([FromBody] dynamic payload) { string action = payload.action.ToString(); if (_actionMappings.TryGetValue(action, out var requestType)) { // 创建请求实例(如需传递参数,可从payload中反序列化) var request = Activator.CreateInstance(requestType); var result = await _mediator.Send(request as IRequest<object>); return Ok(result); } return BadRequest($"Unsupported action: {action}"); }
优点:新增请求类只需加特性,无需手动更新映射;缺点:启动时反射扫描有轻微性能开销,复杂参数传递需要额外处理反序列化。
方案3:基于类名的直接映射(简化版反射)
如果action字符串和请求类名完全匹配(比如"GetAllOrders"对应GetAllOrdersQuery或GetAllOrdersCommand),可以直接通过类名拼接反射创建实例,无需额外特性或字典注册。
示例代码:
[HttpPost] public async Task<IActionResult> HandleAction([FromBody] dynamic payload) { string action = payload.action.ToString(); // 假设请求类命名规则是{Action}Query或{Action}Command,先尝试Query var requestTypeName = $"YourNamespace.{action}Query"; var requestType = Type.GetType(requestTypeName); if (requestType == null) { // 尝试Command requestTypeName = $"YourNamespace.{action}Command"; requestType = Type.GetType(requestTypeName); } if (requestType != null && typeof(IRequest<object>).IsAssignableFrom(requestType)) { var request = Activator.CreateInstance(requestType); var result = await _mediator.Send(request as IRequest<object>); return Ok(result); } return BadRequest($"Unsupported action: {action}"); }
优点:完全无需手动维护映射,零配置;缺点:对类名命名规则要求严格,灵活性差,参数传递同样需要额外反序列化处理。
内容的提问来源于stack exchange,提问作者KPP
相关产品推荐
相关产品推荐

