.net core 在处理实现通用接口的总线事件时避免动态调用

.net core 在处理实现通用接口的总线事件时避免动态调用,.net-core,reflection,.net-core-3.1,.net Core,Reflection,.net Core 3.1,我最近完成了一门关于使用ASP.NET内核的MicroService和RabbitMQ的课程,并注意到事件处理使用动态调用。代码如下(仅保留相关部分): 但是,仍然使用反射。我理解这是必需的,因为Handle被定义为通用方法(通用接口的一部分),并且接收到的事件是动态构造的 是否有方法重构此代码以避免反射?您可以对接口进行更改吗?@Icepickle-是的,接口可以更改。因此,理论上,您可以在IEventHandler上创建一个句柄(事件),然后调用此句柄,然后可以由实现类重定向?您可以对接口进

我最近完成了一门关于使用ASP.NET内核的MicroService和RabbitMQ的课程,并注意到事件处理使用动态调用。代码如下(仅保留相关部分):

但是,仍然使用反射。我理解这是必需的,因为Handle被定义为通用方法(通用接口的一部分),并且接收到的事件是动态构造的


是否有方法重构此代码以避免反射?

您可以对接口进行更改吗?@Icepickle-是的,接口可以更改。因此,理论上,您可以在
IEventHandler
上创建一个
句柄(事件)
,然后调用此句柄,然后可以由实现类重定向?您可以对接口进行更改吗?@Icepickle-是的,接口可以更改。因此,理论上,您可以在
IEventHandler
上创建
句柄(事件事件)
,然后调用此句柄,然后可以由实现类重定向?
public sealed class RabbitMqBus : IEventBus
{
    private readonly IMediator _mediator;
    private readonly Dictionary<string, List<Type>> _handlers;
    private readonly List<Type> _eventTypes;
}

public void Subscribe<TEvent, THandler>() where TEvent : Event where THandler : IEventHandler<TEvent>
{
    string eventName = typeof(TEvent).Name;
    var handlerType = typeof(THandler);

    if (!_eventTypes.Contains(typeof(TEvent)))
        _eventTypes.Add(typeof(TEvent));

    if (!_handlers.ContainsKey(eventName))
        _handlers.Add(eventName, new List<Type>());

    if (_handlers[eventName].Any(s => s == handlerType))
        throw new ArgumentException($"Handler type {handlerType.Name} is already registered for {eventName}");

    _handlers[eventName].Add(handlerType);

    StartBasicConsume<TEvent>();
}

private async Task ConsumerReceived(object sender, BasicDeliverEventArgs e)
{
    string eventName = e.RoutingKey;
    string message = Encoding.UTF8.GetString(e.Body);

    try
    {
        await ProcessEvent(eventName, message);
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception);
        throw;
    }
}

private async Task ProcessEvent(string eventName, string message)
{
    if (_handlers.ContainsKey(eventName))
    {
        using var scope = _serviceScopeFactory.CreateScope();

        var subscriptions = _handlers[eventName];
        foreach (var subscription in subscriptions)
        {
            var handler = scope.ServiceProvider.GetService(subscription);
            if (handler == null)
                continue;

            //TODO: check if this can be made typed and avoid messy dynamic invocation at the end
            Type eventType = _eventTypes.SingleOrDefault(t => t.Name == eventName);
            object @event = JsonConvert.DeserializeObject(message, eventType);
            Type concreteType = typeof(IEventHandler<>).MakeGenericType(eventType);
            await (Task) concreteType.GetMethod("Handle").Invoke(handler, new[] {@event});
        }
    }
}

public interface IEventHandler
{
}

public interface IEventHandler<in TEvent>: IEventHandler
    where TEvent: Event
{
    Task Handle(TEvent @event);
}
Type eventType = _eventTypes.SingleOrDefault(t => t.Name == eventName);
Event @event = (Event) JsonConvert.DeserializeObject(message, eventType);
Type concreteType = typeof(IEventHandler<>).MakeGenericType(eventType);
await (Task)concreteType.GetMethod(nameof(IEventHandler<Event>.Handle)).Invoke(handler, new object[] { @event });