Настройка разрешения компонентов Autofac / Проблема с общей ко- / контравариантностью

Во-первых, извините за расплывчатый заголовок вопроса. Я не мог придумать более точного.

Для этих типов:

                                                     { TCommand : ICommand }
       «interface»                   «interface»    /
      +-----------+         +----------------------/----+
      | ICommand  |         | ICommandHandler<TCommand> |
      +-----------+         +---------------------------+
            ^               | Handle(command: TCommand) |
            |               +---------------------------+
            |                              ^
            |                              |
      +------------+            +-------------------+
      | FooCommand |            | FooCommandHandler |
      +------------+            +-------------------+
            ^
            |
   +-------------------+
   | SpecialFooCommand |
   +-------------------+

Я хотел бы написать метод Dispatch , который принимает любую команду и отправляет ее соответствующему ICommandHandler <> . Я подумал, что использование контейнера DI (Autofac) может значительно упростить отображение типа команды на обработчик команды:

void Dispatch<TCommand>(TCommand command) where TCommand : ICommand
{
    var handler = autofacContainer.Resolve<ICommandHandler<TCommand>>();
    handler.Handle(command);
}

Допустим, контейнер DI знает обо всех типах, показанных выше. Теперь я звоню:

Dispatch(new SpecialFooCommand(…));

На самом деле это приведет к тому, что Autofac выдаст исключение ComponentNotRegisteredException , поскольку нет ICommandHandler .

Однако в идеале я должен по-прежнему хотел бы, чтобы SpecialFooCommand обрабатывался наиболее подходящим доступным обработчиком команд, т.е. с помощью FooCommandHandler в приведенном выше примере.

Можно ли настроить Autofac для этой цели, возможно, с помощью настраиваемого источника регистрации?


PS: Я понимаю, что может быть фундаментальная проблема ко- / контравариантность мешает (как в следующем примере), и что единственным решением может быть решение, которое вообще не использует дженерики ... но я бы хотел придерживаться общих типов, если это возможно.

ICommandHandler<FooCommand> fooHandler = new FooCommandHandler(…);
ICommandHandler<ICommand> handler = fooHandler;
//                                ^
//              doesn't work, types are incompatible
18
задан stakx supports GoFundMonica 10 August 2011 в 11:43
поделиться