我想用泛型编写一个命令处理器。其思想是通过单个对象(commandprocessor本身)发出命令,然后标识处理给定命令的命令处理程序。
但是,以下代码无法编译,我无法理解原因:

class GenericCommandProcessor : ICommandProcessor
{
    private readonly IDictionary<Type, IList<ICommandHandler<ICommand>>> _handlers =
        new Dictionary<Type, IList<ICommandHandler<ICommand>>>();

    public void Register<TCommand>(ICommandHandler<TCommand> handler)
        where TCommand : ICommand
    {
        IList<ICommandHandler<ICommand>> handlers = GetHandlers<TCommand>();
        handlers.Add(handler); // <-- This doesn't compile
    }

    public void Process<TCommand>(TCommand command)
        where TCommand : ICommand
    {
        IList<ICommandHandler<ICommand>> handlers = GetHandlers<TCommand>();

        foreach (var commandHandler in handlers)
        {
            commandHandler.Handle(command);
        }
    }

    private IList<ICommandHandler<ICommand>> GetHandlers<TCommand>()
    {
        Type commandType = typeof(TCommand);

        IList<ICommandHandler<ICommand>> handlers;
        if (!_handlers.TryGetValue(commandType, out handlers))
        {
            handlers = new List<ICommandHandler<ICommand>>();
            _handlers.Add(commandType, handlers);
        }
        return handlers;
    }
}

这是不编译的行:
handlers.Add(handler);

编译器返回以下错误:
cannot convert from 'GenericCommandHandlerTest.ICommandHandler<TCommand>' to 'GenericCommandHandlerTest.ICommandHandler<GenericCommandHandlerTest.ICommand>'

我希望它是这样,因为Register()有一个通用约束:
where TCommand : ICommand

我通过从ioc(castle windsor在我的例子中是castle windsor)解析命令处理程序列表来避免这个问题,而使用注册处理程序列表字典,但是我很想理解为什么在clr级别,这段代码不能编译。我想我只是看不见树木的树林…
多谢提前。

最佳答案

把你的方法改成:

public void AddListItem(IListItem listItem)
{
    _items.Add(listItem);
}

这里不需要使用泛型。
正如其他人已经说过的:即使没有更改,您的代码也会编译,所以请更新您的示例代码。
修复示例后更新:
不能将ICommandHandler<TCommand>类型的变量添加到IList<ICommandHandler<ICommand>>,因为ICommandHandler<ICommand>ICommandHandler<TCommand>是两种不同的类型,尽管TCommand实现ICommand。如果可以的话,我的第一个答案将是正确的,你不需要首先使你的方法通用。
我想Covariance在这里会有帮助,但不幸的是,在这种情况下它不受支持。

09-08 07:44