您可以将通用操作<>或 Func<> 参数与 where 子句一起使用吗?



我不确定我是否遗漏了什么,或者只是不了解编译器的工作方式......基本上,我希望能够传递带有约束参数的操作,而无需重新转换它。将以下代码与有效的强制转换一起获取:

    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 约束只能由方法签名理解,而代码的其余部分忽略了此指令?

Action的第一个通用参数是逆变而不是协变Action<ICommand>不是Action<SomeCommand>的子类型。 事实上,情况正好相反。 Action<SomeCommand>Action<ICommand>的一个子类型

现在,您有一个只能执行的操作 SomeCommand 。 如果你能把它投到Action<ICommand>那么有人可以EvilCommand传递,但EvilCommand不是一种SomeCommand。 另一方面,如果您编写了一个可以接受任何类型的ICommand的方法,那么显然您可以假装它是一个只接受SomeCommand对象的方法,因为您知道所有这些对象都将实现ICommand

第一个解决方案之所以有效,是因为您引入了参数的显式强制转换。 您正在创建一个新方法,该方法执行所需的特定类型检查。 除了工作之外,在这种特定情况下,它也是正确的设计;这是罕见的情况之一,你知道对象实际上是一个TCommand实例,而不仅仅是一个ICommand,但编译器无法证明这一点,并且没有任何真正好的方法来重新设计应用程序,以便它可以静态验证这一点。

最新更新