I'm trying to understand contravariance in practice. It seemed to be straightforward when I read the book, but now I seem to have stuck. I understand there's a lot of topics on contravariance and I've googled many of them, none helped me understand this particular problem Here's what Microsoft docs say https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance
And here's my code:
using static System.Console;
namespace CSharpTests
{
class Program
{
delegate void Action<T> (T obj);
static void Main(string[] args)
{
Action<Device> b = DeviceAction;
Action<Mouse> d = b; // Error cannot implicitly convert type CSharpTests.Program.Action<CSharpTests.Device> to CSharpTests.Program.Action<CSharpTests.Mouse>
d(new Mouse());
ReadLine();
}
private static void DeviceAction(Device target) {
WriteLine(target.GetType().Name);
}
}
class Device { }
class Mouse : Device { }
}
What is the crucial difference? My code doesn't even compile. As you can see I've got a delegate accepting generic type which, as far as I understand, allows contravariance. But on practice, I got a compile time error. I also try to do it with the "out" parameter and got the same error
using static System.Console;
namespace CSharpTests {
class Program {
delegate void Action<T> (out T obj);
static void Main(string[] args) {
Action<Device> b = DeviceAction;
Action<Mouse> d = b; // Error cannot implicitly convert type CSharpTests.Program.Action<CSharpTests.Device> to CSharpTests.Program.Action<CSharpTests.Mouse>
Mouse m;
d(out m);
ReadLine();
}
private static void DeviceAction(out Device target) {
target = new Device();
WriteLine(target.GetType().Name);
}
}
class Device { }
class Mouse : Device { }
}
Change the signature to delegate void Action<in T>(T arg)
.
Declaring a type parameter as in
indicates contravariance; out
indicates covariance.
You can usually tell which one to use because in
is for inputs (e.g., parameters) and out
is for outputs (e.g., return values).