StructureMap对所有可能的具体实现注册泛型类型 [英] StructureMap register generic types against all possible concrete implementations

查看:194
本文介绍了StructureMap对所有可能的具体实现注册泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下内容:

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< >让我得到以下类型的容器:

I would like to use scanning to register the ICommandHandler<> so that I get the following types in the container:


  • ICommandHandler< ADDUSER> 与具体类型 AddUserHandler

  • ICommandHandler< ADDUSER> 与具体类型 AuditTrailHandler

  • ICommandHandler<AddUser> with concrete type AddUserHandler
  • ICommandHandler<AddUser> with concrete type AuditTrailHandler

我与IRegistrationConvention的执行情况,并在一个点上我尝试这样做。有它的工作,但我不能让我的身边我是如何做的头

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.

我们的目标是能够为特定的ICommand实现像这样执行多个处理程序:

The goal is to be able to execute several handlers for a specific ICommand implementation like so:

// 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

I want the AuditTrailHandler<ICommand> to execute for all concrete implementations of ICommand, hence the need to register them for all types of ICommand.

第二个目标将是如果。我可以注入 ICommandHandlers℃的集合; ICommand的> 进入我的CommandDispatcher而不是容器,但我认为这是不可能的我现在的结构。 。证明我错了,如果你有任何想法

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. Prove me wrong if you have any ideas.

编辑 - 解决

我增加了非通用接口,我的通用接口工具,然后我还添加了一个抽象 CommandHandler< T> 所以我没有实现CanHandle或执行(对象)方法。在我所有的处理程序

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.

这是工作结构:

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的问题,这里是扫描到补充一点:

And since this originally was a StructureMap question, here is the Scan to add this:

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

这使我能够注入一个IEnumerable在我CommandDispatcher和执行,像这样:

This makes me able to inject an IEnumerable in my CommandDispatcher and execute like so:

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

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

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).

这是甜的!

推荐答案

要拥有所有注入命令调度命令处理程序,创建一个新的,非通用 ICommandHandler 接口, ICommandHandler< T>从派生的。它有一个Execute方法,这需要一个对象。缺点是,您的每一个命令处理程序必须实现该方法来调用输入过载:

To have all of the command handlers injected into the command dispatcher, create a new, non-generic ICommandHandler interface which ICommandHandler<T> derives from. It has an Execute method which takes an object. 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);
    }
}

这将使你的指挥调度员有一个构造函数依赖在的IEnumerable< ICommandHandler方式> ,这StructureMap将自动填充

This will enable your command dispatcher to have a constructor dependency on IEnumerable<ICommandHandler>, which StructureMap will automatically populate.

在SendCommand你获得相应的2种方式设置处理程序。基于A型简单的过滤器:

In SendCommand you have 2 ways of getting the appropriate set of handlers. A simple filter based on type:

commandHandlers.OfType<ICommandHandler<T>>

或添加 CanHandle(对象命令) ICommandHandler 接口:

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

第二种方法需要更多的代码,但给你多一点灵活性通过允许您超过只需键入附加的处理程序。这可能使解决您的第一个问题比较容易,通过你的 AuditTrailHandler 总是返回真正 CanHandle

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.

这篇关于StructureMap对所有可能的具体实现注册泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆