简体   繁体   English

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

[英]StructureMap register generic types against all possible concrete implementations

I have the following: 我有以下内容:

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);
    }
}

I would like to use scanning to register the ICommandHandler<> so that I get the following types in the container: 我想使用扫描来注册ICommandHandler <>,以便在容器中获得以下类型:

  • ICommandHandler<AddUser> with concrete type AddUserHandler ICommandHandler<AddUser> ,具体类型为AddUserHandler
  • ICommandHandler<AddUser> with concrete type AuditTrailHandler ICommandHandler<AddUser> ,具体类型为AuditTrailHandler

I have tried this with an implementation of IRegistrationConvention and at one point I had it working but I just cannot get my head around how I did it. 我已经尝试过使用IRegistrationConvention的实现来实现这一点,但有一次我使它起作用了,但是我无法理解如何做到这一点。

The goal is to be able to execute several handlers for a specific ICommand implementation like so: 目标是能够为特定的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);    
   }
}

I want the AuditTrailHandler<ICommand> to execute for all concrete implementations of ICommand, hence the need to register them for all types of ICommand. 我希望AuditTrailHandler<ICommand>AuditTrailHandler<ICommand>的所有具体实现都执行,因此需要为所有ICommand类型注册它们。

Secondary objective would be if I could inject a collection of ICommandHandlers<ICommand> into my CommandDispatcher instead of the container, but I think that's impossible with the structure I have now. 第二个目标是是否可以将ICommandHandlers<ICommand>集合而不是容器注入到CommandDispatcher中,但是我认为对于现在的结构这是不可能的。 Prove me wrong if you have any ideas. 如果您有任何想法,请证明我错了。

EDIT - solved 编辑-解决

I added a non generic interface that my generic interface implements and then I also added an Abstract CommandHandler<T> so I don't have to implement the CanHandle or Execute(object) methods in all my handlers. 我添加了一个由我的通用接口实现的非通用接口,然后还添加了一个Abstract CommandHandler<T>所以我不必在所有处理程序中都实现CanHandle或Execute(object)方法。

This is the working structure: 这是工作结构:

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;
    }
}

And since this originally was a StructureMap question, here is the Scan to add this: 并且由于这最初是一个StructureMap问题,因此这里是Scan来添加以下内容:

Scan(x =>
        {
            x.AssemblyContainingType<MyConcreteHandler>();
            x.IncludeNamespaceContainingType<MyConcreteHandler>();
            x.AddAllTypesOf<ICommandHandler>();
            x.WithDefaultConventions();
        });

This makes me able to inject an IEnumerable in my CommandDispatcher and execute like so: 这使我能够在CommandDispatcher中注入IEnumerable并像这样执行:

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);    
        }
    }

This makes me able to execute CommandHandlers that support AddUser (like the AddUserHandler), but I'm also able to execute a handler that support ICommand (like the AuditTrailHandler). 这使我能够执行支持AddUser的CommandHandler(例如AddUserHandler),但是我也能够执行支持ICommand的处理程序(例如AuditTrailHandler)。

This is sweet! 真甜!

To have all of the command handlers injected into the command dispatcher, create a new, non-generic ICommandHandler interface which ICommandHandler<T> derives from. 要将所有命令处理程序注入命令调度程序中,请创建一个新的非通用ICommandHandler接口,该接口从ICommandHandler<T>派生。 It has an Execute method which takes an object. 它具有一个带对象的Execute方法。 The downside is that each of your command handlers has to implement that method to call the typed overload: 缺点是每个命令处理程序都必须实现该方法以调用类型的重载:

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

This will enable your command dispatcher to have a constructor dependency on IEnumerable<ICommandHandler> , which StructureMap will automatically populate. 这将使您的命令调度程序具有对IEnumerable<ICommandHandler>的构造函数依赖关系,StructureMap将自动填充该依赖关系。

In SendCommand you have 2 ways of getting the appropriate set of handlers. 在SendCommand中,您有2种方法来获取适当的处理程序集。 A simple filter based on type: 基于类型的简单过滤器:

commandHandlers.OfType<ICommandHandler<T>>

or add a CanHandle(object command) to the ICommandHandler interface: 或向ICommandHandler接口添加CanHandle(object command)

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

The second approach requires more code, but gives you a little more flexibility by allowing you to attach handler by more than just type. 第二种方法需要更多的代码,但是通过允许您不仅仅通过类型来附加处理程序,还为您提供了更多的灵活性。 This may make solving your first problem easier, by making your AuditTrailHandler always return true from CanHandle . 这可能使解决您的第一个问题比较容易,通过使您AuditTrailHandler总是返回trueCanHandle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM