2

我想维护一个代表列表(这里:“mCommandHandlers”)。由于它们是通用代表,我实际上定义了第二种类型的代表,以便我可以维护这样一个列表:

public delegate void CommandHandler<TCommand>(TCommand command) where TCommand : ICommand;
public delegate void ICommandHandler(ICommand command);
Dictionary<Type, ICommandHandler> mCommandHandlers;

我会使用第一种类型来获得编译时优势,例如确切地知道在我的委托的实现中使用了哪种 TCommand:

RegisterHandler<ResourceCommand>((command) =>
{
       if (command != null)
       {
            ResourceManager.ResourceReceived(command.ResourceName, command.ResourceHash, command.ResourceData);
       }
});

在 RegisterHandler 内部,我现在想做以下事情:

public void RegisterHandler<TCommand>(CommandHandler<TCommand> handler) where TCommand : ICommand
{
      mCommandHandlers.Add(typeof(TCommand), handler);
}

但我收到以下错误消息:

错误 3 参数 2:无法转换 CommandHandler<TCommand>''ICommandHandler'

为什么是这样?编译器是否应该看到事实上我的第一个委托类型要求参数至少是 ICommand 类型,以确保委托实例也符合第二个委托类型的签名?

4

2 回答 2

3

问题是这两种委托类型根本不兼容。为了完成这项工作,您将需要添加一个间接层来转换 和 之间的ICommand参数TCommand

public void RegisterHandler<TCommand>(CommandHandler<TCommand> handler)
  where TCommand : ICommand
{
  mCommandHandlers.Add(
    typeof(TCommand), 
    (command) => handler((TCommand)command);
  );
}
于 2013-08-20T21:30:51.323 回答
2

编译器是否应该看到事实上我的第一个委托类型要求参数至少是 ICommand 类型,以确保委托实例也符合第二个委托类型的签名?

这里有两个问题。

首先,委托变体不允许将一种委托类型隐式引用转换为另一种委托类型——它允许您从兼容的现有委托实例创建一个新的委托实例。

其次,你得到的方差错误的方式CommandHandler<TCommand>只会接受特定类型的命令......而ICommandHandler将接受任何 ICommand.

所以假设我们可以这样做:

CommandHandler<FooCommand> fooHandler = HandleFoo;
ICommandHandler generalHandler = new ICommandHandler(fooHandler);

然后我们可以调用:

generalHandler(new BarCommand());

...您希望该HandleFoo方法如何应对?

对任何特定的都有从to转换,因为当调用新委托时,这将始终有效。示例代码:ICommandHandlerCommandHandler<TCommand>TCommand

using System;

delegate void CommandHandler<TCommand>(TCommand command)
    where TCommand : ICommand;
delegate void ICommandHandler(ICommand command);

interface ICommand {}

class Command : ICommand {}

class Test
{
    public static void Main()
    {
        ICommandHandler x = null;
        CommandHandler<Command> y = new CommandHandler<Command>(x);
    }
}

我建议您将字典更改为:

Dictionary<Type, Delegate> mCommandHandlers;

然后,当您需要调用任何特定的委托时,您需要转换为正确类型的处理程序——我假设您会因为此时的类型参数而知道。或者,您可以根据 Jared 的回答创建一个执行强制转换的代理处理程序。

于 2013-08-20T21:32:04.763 回答