StructureMap针对所有可能的具体实现注册generics类型

我有以下内容:

public interface ICommand { } public class AddUser : ICommand { public string Name { get; set; } public string Password { get; set; } } public interface ICommandHandler : IHandler where T : ICommand { void Execute(T command); } public class AddUserHandler : ICommandHandler { public void Execute(AddUser command) { Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name); } } public class AuditTrailHandler : ICommandHandler { public void Execute(ICommand command) { Console.WriteLine("{0}: Have seen a command of type {1}", GetType().Name, command.GetType().Name); } } 

我想使用扫描来注册ICommandHandler ,以便在容器中获得以下类型:

  • ICommandHandler ,具体类型为AddUserHandler
  • ICommandHandler ,具体类型为AuditTrailHandler

我已经通过IRegistrationConvention的实现尝试了这一点,但有一次我让它工作但我无法理解我是如何做到的。

目标是能够为特定的ICommand实现执行多个处理程序,如下所示:

 // A method in CommandDispatcher public void SendCommand(T command) where T : ICommand { var commandHandlers = container.GetAllInstances<ICommandHandler>(); foreach (var commandHandler in commandHandlers) { commandHandler.Execute(command); } } 

我希望AuditTrailHandler执行AuditTrailHandler的所有具体实现,因此需要为所有类型的ICommand注册它们。

次要目标是,如果我可以将ICommandHandlers的集合注入我的CommandDispatcher而不是容器中,但我认为现在的结构是不可能的。 如果您有任何想法,请certificate我错了。

编辑 – 解决了

我添加了我的通用接口实现的非generics接口,然后我还添加了一个Abstract CommandHandler因此我不必在所有处理程序中实现CanHandle或Execute(对象)方法。

这是工作结构:

 public interface ICommandHandler { void Execute(object command); bool CanHandle(ICommand command); } public interface ICommandHandler : ICommandHandler, IHandler where T : ICommand { void Execute(T command); } public abstract class AbstractCommandHandler : ICommandHandler 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(); x.IncludeNamespaceContainingType(); x.AddAllTypesOf(); x.WithDefaultConventions(); }); 

这使我能够在我的CommandDispatcher中注入IEnumerable并执行如下:

 public void SendCommand(T command) where T : ICommand { var commandHandlersThatCanHandle = commandHandlers.Where(c => c.CanHandle(command)); foreach (var commandHandler in commandHandlersThatCanHandle) { commandHandler.Execute(command); } } 

这使我能够执行支持AddUser的CommandHandler(如AddUserHandler),但我也能够执行支持ICommand的处理程序(如AuditTrailHandler)。

这太好了!

要将所有命令处理程序注入命令调度程序,请创建ICommandHandler派生的新的非通用ICommandHandler接口。 它有一个Execute方法,它接受一个对象。 缺点是每个命令处理程序都必须实现该方法来调用类型化的重载:

 public class AddUserHandler : ICommandHandler { public void Execute(object command) { Execute((AddUser)command); } public void Execute(AddUser command) { Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name); } } 

这将使您的命令调度程序对IEnumerable具有构造函数依赖关系,StructureMap将自动填充。

在SendCommand中,您有两种方法可以获取适当的处理程序集。 一个基于类型的简单filter:

 commandHandlers.OfType> 

或者将CanHandle(object command)添加到ICommandHandler接口:

 commandHandlers.Where(x => x.CanHandle(command)) 

第二种方法需要更多代码,但允许您通过不仅仅键入来附加处理程序,从而为您提供更多灵活性。 通过使CanHandle始终从CanHandle返回true ,这可以使您更容易解决第一个问题。