I am not sure if I am missing something or just not understanding the way in which the complier works... Basically I want to be able to pass an action with a constrained parameter without having to recast it. Take the below code with the cast which works:

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

The following throws an error and says that a parameter of TCommand can't be passed as an ICommand

    public void Register<TCommand>(Action<TCommand> action) where TCommand : ICommand
    {
        _dictionary.Add(typeof(TCommand), action);
    }

Am I doing something wrong or is it that the where constraint is only understood by the method signature and the rest of the code ignores this directive?

有帮助吗?

解决方案

The first generic argument to Action is contravariant not covariant. Action<ICommand> is not a sub-type of Action<SomeCommand>. In fact, it's the other way around. Action<SomeCommand> is a sub type of Action<ICommand>!

Right now you have an action that can take only a SomeCommand. If you could cast it to Action<ICommand> then someone could pass in an EvilCommand, but an EvilCommand is not a type of SomeCommand. On the other hand, if you've written a method that can accept any type of ICommand, then obviously you could pretend that it was a method that only accepts SomeCommand objects, because you know all of them will implement ICommand.

Your first solution works because you're introducing the explicit cast of the parameter. You're creating a new method, one that performs the specific type check needed. In addition to working, it is also the correct design in this specific case; it's one of those rare situations where you know that the object is in fact a TCommand instance, not just an ICommand, but the compiler can't prove it, and there aren't any really good ways of re-designing the application such that it could statically verify that.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top