Ambiguous call on an Action where T inherits 2

2019-09-02 12:59发布

问题:

I have the following code:

public class MyClass
{
    public void MyMethod()
    {
        Action<Child> aFoo = a => a.Foo();
    }
}

interface Parent1
{
    void Foo();
}

interface Parent2
{
    void Foo();
}

interface Child : Parent1, Parent2
{

}

However, the compiler tells me that I have an ambiguous call on aFoo.

I tried to do Action<Child> aFoo = (A a) => a.Foo(); but it tells me that I cannot convert lambda expression to delegate type System.Action<Child>

How do I resolve the error of ambiguity?

回答1:

By casting the value of a inside the body of the lambda:

Action<Child> aFoo = a => ((Parent1)a).Foo();

Your attempted solution did not work because it did something else entirely: it tried to fit a lambda expression taking a Parent1 into a delegate taking a Child. This is not possible, even though it is possible to fit a delegate taking a Parent1 into a delegate taking a Child:

Action<Child> aFoo = (Action<Parent1>)(a => a.Foo());

This latter usage is viable because Action<T> is contravariant on the type T.



回答2:

Action<T> is not covariant in its type parameter T, it is contravariant. That means Action<object> can be converted to Action<string>, but not the other way around.

Generally put, Action<T> is a subtype of (read: can be assigned to) Action<U>, only if U is a subtype of T.

In your case, Child is a subclass of Parent, which means Action<Parent> is a subclass of Action<Child>, allowing you to do this:

Action<Child> a = new Action<Parent> (... );

But not:

Action<Parent> a = new Action<Child>( ... );

That being said, try casting the lambda parameter instead:

Action<C> aFoo = a => ((A)a).Foo();