У меня есть следующее:
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);
}
}
Я бы хотел использовать сканирование для регистрации ICommandHandler <>, чтобы в контейнере были следующие типы:
ICommandHandler<AddUser>
с типом бетона AddUserHandler
ICommandHandler<AddUser>
с конкретным типом AuditTrailHandler
Я попробовал это с реализацией IRegistrationConvention, и в какой-то момент у меня это заработало, но я просто не могу понять, как я это сделал.
Цель состоит в том, чтобы иметь возможность выполнить несколько обработчиков для конкретной реализации ICommand, например:
// 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);
}
}
Я хочу, чтобы AuditTrailHandler<ICommand>
выполнялся для всех конкретных реализаций ICommand, поэтому необходимо регистрировать их для всех типов ICommand.
Вторичной целью было бы, если бы я мог вставить коллекцию ICommandHandlers<ICommand>
в мой CommandDispatcher вместо контейнера, но я думаю, что это невозможно с той структурой, которая у меня есть сейчас. Докажите, что я не прав, если у вас есть идеи.
РЕДАКТИРОВАТЬ - решено
Я добавил не универсальный интерфейс, который реализует мой универсальный интерфейс, а затем я также добавил Abstract CommandHandler<T>
, поэтому мне не нужно реализовывать методы CanHandle или Execute (object) во всех моих обработчиках.
Это рабочая структура:
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;
}
}
И так как это изначально был вопрос StructureMap, вот Сканирование, чтобы добавить это:
Scan(x =>
{
x.AssemblyContainingType<MyConcreteHandler>();
x.IncludeNamespaceContainingType<MyConcreteHandler>();
x.AddAllTypesOf<ICommandHandler>();
x.WithDefaultConventions();
});
Это позволяет мне вставлять IEnumerable в мой CommandDispatcher и выполнять так:
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);
}
}
Это позволяет мне выполнять CommandHandlers, которые поддерживают AddUser (например, AddUserHandler), но я также могу выполнять обработчик, который поддерживает ICommand (например, AuditTrailHandler).
Это сладко!