Yuri Dorokhov Yuri Dorokhov - 3 months ago 9
C# Question

Parameter must be input-safe error

Here is a piece of my code:

public interface IA<in TInput>
{
void Method(IB<TInput> entities);
}

public interface IB<in T> { }


I can't figure out why I get following compile error:
"Parameter must be input-safe. Invalid variance: The type parameter |TInput| must be contravariantly valid on "IB< in T>".

Any help will be appreciated.

Answer

The designator of contravariance in C# (i.e. in) is intuitive only at the immediate level, when you make a method that "takes in" a parameter of generic type. Internally, however, contravariance means an inversion of a relation (Q&A with an explanation) so using in inside IA makes it incompatible with IB.

The problem is best illustrated with an example. Consider class Animal and its derived class Tiger. Let's also assume that IB<T> has a method void MethodB(T input), which is called from IA's Method:

class A_Impl<T> : IA<T> {
    T data;
    public void Method(IB<TInput> entities) {
        entities.MethodB(data);
    }
}

Declaring IA<in TInput> and IB<in TInput> means that you can do

IA<Animal> aForAnimals = new A_Impl<Animal>();
IA<Tiger> aForTigers = aForAnimals;

IA<in TInput> has a method that takes IB<TInput>, which we can call like this:

aForTigers.Method(new B_Impl<Tiger>());

This is a problem, because now A_Impl<Animal> passes an Animal to MethodB of an interface that expects a Tiger.

You would have no problem with IB<out T>, though - both with covariance and contravariance:

public interface IB<out T> {
//                  ^^^
}
// This works
public interface IA<in TInput> {
    void Method(IB<TInput> x);
}
// This works too
public interface IC<out TInput> {
    void Method(IB<TInput> x);
}
Comments