Во-первых, извините за неопределенное название вопроса. Я не мог придумать более точный.
Учитывая эти типы:
{ 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>
.
В идеале, однако, мне бы хотелось, чтобы SpecialFooCommand
обрабатывался доступным обработчиком ближайшего соответствия, т.е. на FooCommandHandler
в приведенном выше примере.
Можно ли настроить Autofac с этой целью, возможно, с помощью настраиваемого источника регистрации?
PS: Я понимаю, что может возникнуть фундаментальная проблема совпадения/контравариантности (как в следующем примере), и единственным решением может быть то, что не использовать общие файлы вообще... но я хотел бы придерживаться общих типов, если это возможно.
ICommandHandler<FooCommand> fooHandler = new FooCommandHandler(…);
ICommandHandler<ICommand> handler = fooHandler;
// ^
// doesn't work, types are incompatible