我不确定我是否遗漏了某些东西或者只是不理解编译器的工作方式...基本上我希望能够通过约束参数传递一个动作,而不必重新制作它。使用下面的代码与演员工作:
private readonly Dictionary<Type, Action<ICommand>> _dictionary = new Dictionary<Type, Action<ICommand>>();
public void Register<TCommand>(Action<TCommand> action) where TCommand : ICommand
{
_dictionary.Add(typeof(TCommand), x => action((TCommand)x));
}
以下引发错误并说TCommand的参数不能作为ICommand传递
public void Register<TCommand>(Action<TCommand> action) where TCommand : ICommand
{
_dictionary.Add(typeof(TCommand), action);
}
我做错了什么,或者 where 约束只能被方法签名理解,其余的代码会忽略这个指令吗?
答案 0 :(得分:2)
Action
的第一个通用参数是逆变而非协变。 Action<ICommand>
不是Action<SomeCommand>
的子类型。事实上,它是相反的方式。 Action<SomeCommand>
是 Action<ICommand>
的子类型!
现在你的行动只能采用SomeCommand
。如果您可以将其投放到Action<ICommand>
,则有人可以传入EvilCommand
,但EvilCommand
不是SomeCommand
的类型。另一方面,如果您编写的方法可以接受任何类型的ICommand
,那么显然您可以假装它是一种只接受SomeCommand
个对象的方法,因为您 know 所有这些都将实现ICommand
。
您的第一个解决方案有效,因为您正在引入参数的显式强制转换。您正在创建新方法,该方法执行所需的特定类型检查。除了工作之外,它也是这种特殊情况下的正确设计;它是你知道对象实际上是TCommand
实例的罕见情况之一,而不仅仅是ICommand
,但编译器可以&#39;证明这一点,并没有任何真正好的方法来重新设计应用程序,以便它可以静态验证。