Во-первых, извините за расплывчатый заголовок вопроса. Я не мог придумать более точного.
Для этих типов:
{ 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