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

如何将现有事件/通知及处理器适配到MediatR,无需额外实现?

适配现有事件系统到MediatR的方案

这问题我之前帮团队落地过类似的需求,核心是靠MediatR的开放泛型支持和适配器模式,完全不用给每种现有事件/处理器额外写重复代码。咱们一步步来:

先对齐现有结构(先明确上下文)

假设你的现有代码大概是这样的(如果和实际有出入,调整下泛型约束就行):

// 现有事件标记接口
public interface IEvent { }

// 现有处理器接口
public interface IEventHandler<TEvent> where TEvent : IEvent
{
    void Handle(TEvent @event);
    // 如果是异步逻辑就是 Task Handle(TEvent @event);
}

// 具体事件示例
public class OrderCreatedEvent : IEvent
{
    public Guid OrderId { get; set; }
}

// 对应的现有处理器
public class OrderCreatedHandler : IEventHandler<OrderCreatedEvent>
{
    public void Handle(OrderCreatedEvent @event)
    {
        // 原有处理逻辑
        Console.WriteLine($"处理订单创建事件:{@event.OrderId}");
    }
}

步骤1:创建MediatR通知适配器

把你的IEvent包装成MediatR能识别的INotification类型,用泛型适配器统一处理:

// 泛型适配器,将任意IEvent转换为MediatR的INotification
public class EventNotificationAdapter<TEvent> : INotification where TEvent : IEvent
{
    public TEvent Event { get; }

    public EventNotificationAdapter(TEvent @event)
    {
        Event = @event;
    }
}

步骤2:创建通用处理器适配器

把现有IEventHandler<T>适配成MediatR的INotificationHandler<EventNotificationAdapter<T>>,这样所有现有处理器都能被MediatR调用:

// 同步版本适配器
public class EventHandlerAdapter<TEvent> : INotificationHandler<EventNotificationAdapter<TEvent>> 
    where TEvent : IEvent
{
    private readonly IEventHandler<TEvent> _existingHandler;

    // 通过依赖注入拿到现有处理器
    public EventHandlerAdapter(IEventHandler<TEvent> existingHandler)
    {
        _existingHandler = existingHandler;
    }

    public Task Handle(EventNotificationAdapter<TEvent> notification, CancellationToken cancellationToken)
    {
        // 调用现有处理器的Handle方法
        _existingHandler.Handle(notification.Event);
        return Task.CompletedTask;
    }
}

// 如果你的现有处理器是异步的,就用这个版本:
// public class AsyncEventHandlerAdapter<TEvent> : INotificationHandler<EventNotificationAdapter<TEvent>> 
//     where TEvent : IEvent
// {
//     private readonly IEventHandler<TEvent> _existingHandler;
//
//     public AsyncEventHandlerAdapter(IEventHandler<TEvent> existingHandler)
//     {
//         _existingHandler = existingHandler;
//     }
//
//     public Task Handle(EventNotificationAdapter<TEvent> notification, CancellationToken cancellationToken)
//     {
//         return _existingHandler.Handle(notification.Event, cancellationToken);
//     }
// }

步骤3:依赖注入注册关键类型

不管你用的是Microsoft原生DI还是Autofac,核心是注册开放泛型,让容器自动为每个IEvent类型匹配对应的适配器:

原生DI示例

services.AddMediatR(cfg =>
{
    // 扫描注册所有现有处理器(指定包含处理器的程序集即可)
    cfg.RegisterServicesFromAssemblyContaining<OrderCreatedHandler>();
});

// 注册通用处理器适配器(开放泛型)
services.AddScoped(typeof(INotificationHandler<>), typeof(EventHandlerAdapter<>));

Autofac示例

builder.RegisterAssemblyTypes(typeof(OrderCreatedHandler).Assembly)
       .AsClosedTypesOf(typeof(IEventHandler<>));

builder.RegisterGeneric(typeof(EventHandlerAdapter<>))
       .As(typeof(INotificationHandler<>))
       .InstancePerLifetimeScope();

builder.RegisterMediatR(typeof(Program).Assembly);

步骤4:分发事件到MediatR

现在你只需要把原有IEvent包装成适配器,然后用MediatR的IPublisher发布即可:

public class EventDispatcher
{
    private readonly IPublisher _mediatorPublisher;
    // 缓存泛型适配器类型,避免重复反射开销
    private static readonly Dictionary<Type, Type> _adapterTypeCache = new();

    public EventDispatcher(IPublisher mediatorPublisher)
    {
        _mediatorPublisher = mediatorPublisher;
    }

    public async Task PublishEvent(IEvent @event)
    {
        var eventType = @event.GetType();
        if (!_adapterTypeCache.TryGetValue(eventType, out var adapterType))
        {
            adapterType = typeof(EventNotificationAdapter<>).MakeGenericType(eventType);
            _adapterTypeCache[eventType] = adapterType;
        }
        
        // 创建适配器实例并发布
        var adapter = Activator.CreateInstance(adapterType, @event);
        await _mediatorPublisher.Publish(adapter, CancellationToken.None);
    }
}

额外注意点

  • 如果你的现有事件系统支持多处理器(一个事件对应多个处理器),MediatR天然支持,适配器会自动调用所有匹配的现有处理器。
  • 要是需要统一处理异常,可以在适配器里加try/catch,或者利用MediatR的行为管道(Behavior)做全局拦截。
  • 反射创建适配器的部分已经加了缓存,避免重复反射的性能损耗,如果有需要还可以用表达式树进一步优化。

内容的提问来源于stack exchange,提问作者Esben Bach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:27:28