Разрешение перечислимых зависимостей Autofac без контравариантности - PullRequest
0 голосов
/ 16 января 2019

Мое приложение имеет два класса команд FooCommand и BarCommand, где BarCommand является подклассом FooCommand.

class FooCommand
class BarCommand : FooCommand

У меня есть классы для выполнения этих команд.

class FooCommandHandler : ICommandHandler<FooCommand>
class BarCommandHandler : ICommandHandler<BarCommand>

Эти обработчики команд зарегистрированы в Autofac как ICommandHandler<> services.

builder.RegisterType<FooCommandHandler>.As<ICommandHandler<FooCommand>>();
builder.RegisterType<BarCommandHandler>.As<ICommandHandler<BarCommand>>();

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

var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<FooCommand>>>()
// returns [ FooCommandHandler ]

Пока все хорошо. Но когда я разрешаю зарегистрированные обработчики для BarCommand, Autofac совпадает с реализациями BarCommandHandler и FooCommandHandler, потому что BarCommand происходит от FooCommand.

var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<BarCommand>>>()
// returns [ BarCommandHandler, FooCommandHandler ]

Это поведение не слишком неожиданно, но это не совсем то, что я хочу.

Есть ли способ разрешить IEnumerable<ICommandHandler<BarCommand>> для предоставления только тех обработчиков, которые непосредственно реализуют интерфейс ICommandHandler<BarCommand>, не включая также те, которые реализуют ICommandHandler<Base>?

1 Ответ

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

Слишком долго для комментария: я не могу дублировать поведение. Вот несколько типов и юнит-тест:

public interface ICommandHandler<T> where T : FooCommand { }
public class FooCommand { }
public class BarCommand : FooCommand { }
class FooCommandHandler : ICommandHandler<FooCommand> { }
class BarCommandHandler : ICommandHandler<BarCommand> { }
class BarCommandHandler2 : ICommandHandler<BarCommand> { }

[TestClass]
public class AutofacTests
{
    [TestMethod]
    public void ContainerResolvesExpectedDependency()
    {
        var container = GetContainer();
        var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<BarCommand>>>()
            .ToArray();
        Assert.AreEqual(2, barCommandHandlers.Length);
        Assert.IsTrue(barCommandHandlers.Any(bch => bch is BarCommandHandler));
        Assert.IsTrue(barCommandHandlers.Any(bch => bch is BarCommandHandler2));
        Assert.IsFalse(barCommandHandlers.Any(bch => bch is FooCommandHandler));
    }

    private IContainer GetContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<FooCommandHandler>().As<ICommandHandler<FooCommand>>();
        builder.RegisterType<BarCommandHandler>().As<ICommandHandler<BarCommand>>();
        builder.RegisterType<BarCommandHandler2>().As<ICommandHandler<BarCommand>>();
        return builder.Build();
    }
}

Я регистрирую различные реализации ICommandHandler<T>. Я включил дополнительный - BarCommandHandler2 - чтобы я мог убедиться, что я получаю коллекцию нескольких реализаций из контейнера.

Тесты пройдены. Я регистрирую все три типа, но когда я решаю IEnumerable<ICommandHandler<BarCommand>>, я получаю только две реализации, которые ожидаю.

Это имеет смысл, потому что FooCommandHandler не реализует ICommandHandler<BarCommand>. Если контейнер разрешит это, то это будет ошибка.

Я бы порекомендовал просмотреть ту часть, в которой вы решаете IEnumerable<ICommandHandler<BarCommand>>. Возможно, у вас есть дополнительные генерики на работе, и во время выполнения вы на самом деле решаете что-то еще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...