Решение смешанных открытых-закрытых дженериков с замком Виндзор - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь разрешить смешанный открытый-закрытый универсальный тип с ограничениями, используя Castle Windsor. Это должно быть в состоянии разрешить любые открытые обобщения, если Foo реализует IFoo <>:

container.Register(Component.For(typeof(IFoo<>).ImplementedBy(typeof(Foo<>)));

Моя ситуация немного сложнее:

У меня есть Handler класс:

public abstract class CommandHandlerBase<TCommand, TResponse>
    : IRequestHandler<TCommand, TResponse>
    where TCommand : IRequest<TResponse>
{
    public abstract Task<TResponse> Handle(
        TCommand request, CancellationToken cancellationToken);
}

public class AddMasterDataEntityCommandHandler<TNewEntityData>
    : IRequestHandler<TNewEntityData, Response>
    where TNewEntityData : IRequest<Response>
{
    public Task<Response> Handle(
        TNewEntityData request, CancellationToken cancellationToken)
    {
       // ...
    }
}

Идея состоит в том, что AddMasterDataEntityCommandHandler будет универсальным обработчиком команд, который может обрабатывать контракты любого типа типа TNewEntityData.

Поскольку я использую Mediatr , мои контракты должны выполнять IRequest<,>, что они и делают. В этом случае я обязую все обработчики возвращать Response.

Пример использования:

Response response = await mediator.Send(new AddMasterDataEntityCommand<NewPlace>());

Я создал простое консольное приложение, чтобы изолировать это поведение:

    public static void Main(string[] args)
    {
        var container = new WindsorContainer();

        container.Register(Types.FromThisAssembly()
                                .BasedOn(typeof(IRequestHandler<,>))
                                .Unless(t => t.IsAbstract || t.IsInterface)
                                .WithServices(typeof(IRequestHandler<,>))
                                .LifestyleTransient());

        var instance = container.Resolve(typeof(IRequestHandler<NewData, Response>));
    }

Однако тест выдает исключение, указывающее на ошибку в моем коде:

Castle.MicroKernel.Handlers.GenericHandlerTypeMismatchException: 'Типы ConsoleApp4.NewData, ConsoleApp4.Response не удовлетворяют общим ограничениям типа реализации ConsoleApp4.AddMasterDataEntityCommandHandler'1 для компонента' ConsoleAppDataDHD.Data.HD. Скорее всего, это ошибка в вашем коде. '

Я не вижу здесь проблемы, CW должен иметь возможность разрешать открытые / закрытые генерики, верно? Кроме того, проблема, похоже, связана с дополнительным параметром Response типа TResponse. Я неправильно зарегистрировал компонент? Я уверен, что не испортил общие ограничения ...

Заранее спасибо всем, кто может взглянуть.

1 Ответ

0 голосов
/ 16 января 2019

Кшиштоф Козьмич повел меня в правильном направлении:

Сначала я попробовал реализацию с IGenericImplementationMatchingStrategy, но не смог заставить это работать, только имея возможность обрабатывать тип с одним универсальным. Я закончил тем, что регистрировался как немного волшебства отражения:

private void RegisterGenericMasterDataCommandHandlers(IWindsorContainer container) {
    foreach (Type contractType in contractTypes) {
        Type requestedType = typeof(IRequestHandler<,>).MakeGenericType(typeof(AddMasterDataEntityCommand<>).MakeGenericType(contractType), typeof(Response));
        Type implementedType = typeof(AddMasterDataEntityCommandHandler<>).MakeGenericType(contractType);

        container.Register(Component.For(requestedType, implementedType));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...