mediatr并非经典中介者模式实现,而是基于.net的消息路由库,专注请求-响应分发;经典中介者需管理同事引用、状态感知与实时协作,二者适用场景截然不同。

MediatR 不是 C# 原生的中介者模式实现,而是基于 .NET 的第三方库(由 Jimmy Bogard 开发),它把中介者模式做了高度抽象和泛型封装。直接用 MediatR 写业务逻辑,和手写经典中介者模式(IMediator + Colleague)是两回事——前者专注命令/查询分发,后者强调对象间解耦协作。
MediatR 和经典中介者模式根本不是一回事
很多人一看到 MediatR 就以为是在“实现中介者模式”,其实它解决的是不同问题:
-
MediatR是请求-响应管道模型:你发一个IRequest<tresponse></tresponse>,它找对应IRequestHandler<trequest tresponse></trequest>执行,本质是“消息路由+依赖注入驱动” - 经典中介者模式(如
ConcreteMediator协调ColleagueA和ColleagueB)关注运行时对象生命周期内的双向通信、状态感知、条件转发,比如 UI 组件联动、游戏实体交互 -
MediatR默认不持有任何同事对象引用,也不维护对象关系图;而手写中介者必须显式管理colleagueA、colleagueB等实例
什么时候该手写 IMediator 而不是用 MediatR
以下场景用 MediatR 反而绕路、难调试、甚至出错:
- UI 层组件通信:比如
TextBox输入后触发ComboBox刷新,再通知SaveButton启用 —— 这些控件有生命周期、需响应状态变更,MediatR的“一次发、一次收”模型无法表达这种持续协作 - Unity 或游戏逻辑中多个
GameObject实例需要实时感知彼此状态(如碰撞、距离、资源占用)—— 需要中介者持有引用并轮询/事件监听,MediatR无此能力 - 需要根据同事对象当前状态决定是否转发、改写或拦截消息(例如:只有
ColleagueA.IsReady为 true 时才通知ColleagueB)——MediatR的 handler 是无上下文纯函数 - 错误信息如
System.InvalidOperationException: Handler was not found for request往往就源于强行把状态敏感逻辑塞进MediatR管道
手写中介者时最容易漏掉的三件事
写 ConcreteMediator 类时,光实现 Notify() 方法远远不够:
- 忘记在同事类构造时传入中介者引用:同事类必须持有
IMediator,否则无法调用mediator.Notify(this, msg)—— 常见错误是只在中介者里存同事,却没让同事反向持有中介者 - 没处理循环引用风险:如果
ColleagueA发消息给中介者,中介者又调用ColleagueA.Receive(),就会栈溢出。应在Notify中加 sender 判断或引入异步调度(如Task.Run(() => colleague.Receive(msg))) - 忽略线程安全:多个线程同时调用
Notify(),而中介者内部用List<colleague></colleague>存同事列表,可能抛InvalidOperationException: Collection was modified—— 改用ConcurrentBag<colleague></colleague>或加lock
MediatR 注册和使用中的典型陷阱
即使你确定要用 MediatR,也得避开这些坑:
-
AddMediatR(typeof(Startup).Assembly)会扫描整个程序集,若存在未实现IRequestHandler的泛型类(如Handler<t></t>),启动时报错Unable to resolve service for type 'MediatR.IRequestHandler`2[...]' - 在 ASP.NET Core 中,
IMediator是 Scoped 生命周期,但你在BackgroundService里直接注入它,可能遇到Cannot resolve scoped service from root provider—— 必须用IServiceScopeFactory.CreateScope()显式创建作用域 - 发送
INotification时默认并行执行所有 handler,若某个 handler 抛异常,其余 handler 会被中断(除非配置ServiceConfiguration.NotificationPublisher = new TaskWhenAllPublisher())
真正关键的不是选 MediatR 还是手写,而是看通信是否带状态、是否需实时响应、是否跨生命周期——这些决定了中介逻辑该放在服务容器里,还是对象图内部。










