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