O StructureMap registra tipos genéricos em todas as implementações concretas possíveis
Eu tenho o seguinte:
public interface ICommand { }
public class AddUser : ICommand
{
public string Name { get; set; }
public string Password { get; set; }
}
public interface ICommandHandler<T> : IHandler<T> where T : ICommand
{
void Execute(T command);
}
public class AddUserHandler : ICommandHandler<AddUser>
{
public void Execute(AddUser command)
{
Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name);
}
}
public class AuditTrailHandler : ICommandHandler<ICommand>
{
public void Execute(ICommand command)
{
Console.WriteLine("{0}: Have seen a command of type {1}", GetType().Name, command.GetType().Name);
}
}
Eu gostaria de usar a varredura para registrar o ICommandHandler <> para obter os seguintes tipos no contêiner:
ICommandHandler<AddUser>
com tipo de concretoAddUserHandler
ICommandHandler<AddUser>
com tipo de concretoAuditTrailHandler
Eu tentei isso com uma implementação do IRegistrationConvention e, a certa altura, ele funcionava, mas simplesmente não consigo entender como o fiz.
O objetivo é poder executar vários manipuladores para uma implementação específica do ICommand, como:
// A method in CommandDispatcher
public void SendCommand<T>(T command) where T : ICommand {
var commandHandlers = container.GetAllInstances<ICommandHandler<T>>();
foreach (var commandHandler in commandHandlers) {
commandHandler.Execute(command);
}
}
eu quero oAuditTrailHandler<ICommand>
executar para todas as implementações concretas do ICommand, daí a necessidade de registrá-las para todos os tipos de ICommand.
O objetivo secundário seria se eu pudesse injetar uma coleção deICommandHandlers<ICommand>
no meu CommandDispatcher em vez do contêiner, mas acho que é impossível com a estrutura que tenho agora. Prove que estou errado, se você tem alguma idéia.
EDIT - resolvido
Eu adicionei uma interface não genérica que minha interface genérica implementa e também adicionei um resumoCommandHandler<T>
portanto, não tenho que implementar os métodos CanHandle ou Execute (object) em todos os meus manipuladores.
Esta é a estrutura de trabalho:
public interface ICommandHandler
{
void Execute(object command);
bool CanHandle(ICommand command);
}
public interface ICommandHandler<T> : ICommandHandler, IHandler<T> where T : ICommand
{
void Execute(T command);
}
public abstract class AbstractCommandHandler<T> : ICommandHandler<T> where T : ICommand
{
public abstract void Execute(T command);
public void Execute(object command)
{
Execute((T)command);
}
public virtual bool CanHandle(ICommand command)
{
return command is T;
}
}
E como essa era originalmente uma pergunta do StructureMap, aqui está a verificação para adicionar isso:
Scan(x =>
{
x.AssemblyContainingType<MyConcreteHandler>();
x.IncludeNamespaceContainingType<MyConcreteHandler>();
x.AddAllTypesOf<ICommandHandler>();
x.WithDefaultConventions();
});
Isso me permite injetar um IEnumerable no meu CommandDispatcher e executar da seguinte maneira:
public void SendCommand<T>(T command) where T : ICommand
{
var commandHandlersThatCanHandle = commandHandlers.Where(c => c.CanHandle(command));
foreach (var commandHandler in commandHandlersThatCanHandle)
{
commandHandler.Execute(command);
}
}
Isso me permite executar CommandHandlers que oferecem suporte ao AddUser (como o AddUserHandler), mas também posso executar um manipulador que suporte o ICommand (como o AuditTrailHandler).
Isto é doce!