Приведение к универсальному классу, когда тип заполнителя известен только во время выполнения - PullRequest
0 голосов
/ 05 июля 2019

У меня есть немного уродливый кусок кода, потому что я должен использовать отражение, чтобы заставить его работать.Я не могу не задаться вопросом, есть ли лучший / более чистый способ достижения того же самого.

Сценарий следующий: мой код подписывается на хранилище событий.Каждый раз, когда хранилище событий записывает новое событие, выполняется мой метод Task Process(IResolvedEvent resolvedEvent).В настоящее время я сопоставляю (десериализуем) resolvedEvent с его исходным IPersistableEvent и использую его тип для получения из контейнера DI (Autofac) зарегистрированного IEventHandler<TEvent> where TEvent : IPersistableEvent, чтобы я мог обработать это событие с ним.

Как видите, тип события известен только во время выполнения, и мне приходится использовать отражение дважды.Первый раз использовать фабрику, которая получает правильные IEventHandler<TEvent> из контейнера DI, и второй раз вызвать метод Handle в этом экземпляре.

Основная проблема Я бы хотелк рефакторингу относится тот факт, что метод Invoke возвращает объект, и я хочу привести этот объект к IEventHandler<TEvent>, где я знаю TEvent во время выполнения .

Было бы здоровоесли бы я мог сделать что-то вроде этого, это C #:

var eventHandler = (IEventHandler<?>)createMethodGeneric.Invoke(_eventHandlerFactory, null);
await eventHandler.Handle(persistableEvent);

К сожалению, я не могу преобразовать это в универсальный класс таким образом.Можно ли делать литье по-другому с отражением или желательно без отражения?Это мой текущий рабочий код.

public class ResolvedEventDispatcher
    : IResolvedEventDispatcher
{
    private readonly IMapper<IResolvedEvent, IPersistableEvent> _persistableEventMapper;
    private readonly IEventHandlerFactory _eventHandlerFactory;

    public ResolvedEventDispatcher(
        IMapper<IResolvedEvent, IPersistableEvent> persistableEventMapper,
        IEventHandlerFactory eventHandlerFactory)
    {
        _persistableEventMapper = persistableEventMapper;
        _eventHandlerFactory = eventHandlerFactory;
    }

    public async Task Process(IResolvedEvent resolvedEvent)
    {
        try
        {
            var persistableEvent = _persistableEventMapper.Map(resolvedEvent);
            var persistableEventType = persistableEvent.GetType();
            var eventHandlerFactoryType = _eventHandlerFactory.GetType();
            var createMethod =
                eventHandlerFactoryType
                    .GetMethods()
                    .First(x => x.IsGenericMethod);
            var typeArguments =
                new[]
                {
                    persistableEventType
                };
            var createMethodGeneric = createMethod.MakeGenericMethod(typeArguments);

            var eventHandler = createMethodGeneric.Invoke(_eventHandlerFactory, null);
            var eventHandlerType = eventHandler.GetType();
            var handleMethod = eventHandlerType.GetMethod("Handle");

            var parameters =
                new object[]
                {
                    persistableEvent
                };
            await (Task) handleMethod.Invoke(eventHandler, parameters);
        }
        catch (Exception exception)
        {
            var foo = exception;
        }
    }
}

И это фабрика, которую я использую для получения правильного IEventHandler<TEvent> из контейнера DI:

public class EventHandlerFactory
    : IEventHandlerFactory
{
    private readonly IComponentContext _componentContext;

    public EventHandlerFactory(IComponentContext componentContext)
    {
        _componentContext = componentContext;
    }

    public IEventHandler<TEvent> Create<TEvent>() where TEvent : class, IPersistableEvent
    {
        var eventType = typeof(TEvent);
        var eventHandlerType = typeof(IEventHandler<>);
        var typeArguments =
            new[]{
                eventType
            };
        var eventHandlerWithGenericType = eventHandlerType.MakeGenericType(typeArguments);
        var isRegistered = _componentContext.IsRegistered(eventHandlerWithGenericType);
        if (!isRegistered)
        {
            throw new EventHandlerNotRegisteredException($"Could not find any handler for event type {eventType}");
        }
        var eventHandler = _componentContext.Resolve(eventHandlerWithGenericType);
        return (IEventHandler<TEvent>)eventHandler;
    }
}

Наконец, обработчик Iхочу вызвать определяется:

public interface IEventHandler<in TEvent>
    where TEvent : IPersistableEvent
{
    Task Handle(TEvent @event);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...