About
In this code snippet, we’ll take a look at covariance and contravariance in C#.
Covariance and contravariance enable implicit type conversion for arrays, delegates and generic interface type arguments.
Covariance allows for a more derived type to be used where a less derived type is expected. This can be done implicitly because a more derived type contains all the members of a less derived type.
Contravariance allows for a less derived type to be used where a more derived type is expected. This can be done because a less derived type will have all the members the more derived type has.
Let’s have a look at the code below to see an example of covariance and contravariance.
Code:
namespace CovarianceContravariance
{
internal class Program
{
static void Main(string[] args)
{
//To quote https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
//"In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments.
//Covariance preserves assignment compatibility and contravariance reverses it."
//Covariance is when a more derived type is assigned to a less derived one.
Action<string> funcMyMethodString = MyMethod;
Action<string> funcMyMethodObject = funcMyMethodString;
//Contravariance is when a less derived type is assigned to a more derived one.
Action<object> funcMyOtherMethod = MyOtherMethod;
Action<string> funcMyOtherMethodString = funcMyOtherMethod;
}
static void MyOtherMethod(object input)
{
//Do something...
}
static void MyMethod(string input)
{
//Do something...
}
//Generic type parameters in interfaces can be covariant(out keyword) or contravariant(in keyword).
//Covariant interface methods can have a more derived return type than defined by the generic type parameters.
//Contravariant interface methods can have less derived input parameter types than those defined by the generic parameters.
interface MyCovariantInterface<out T>
{
//Methods can return type of T.
T MyMethod();
//Methods can't take type of T as an input parameter.
//void MyOtherMethod(T input); //Throws error if uncommented.
}
interface MYContravariantInterface<in T>
{
//Methods can take type of T as an input parameter.
void MyMethod(T input);
void DoSomething<U>() where U : T; //Type constraints can be specified if desired. I briefly covered constraints in this post: https://eecs.blog/c-generics/
//Methods can't return type of T.
//T MyOtherMethod(); //Throws error if uncommented.
}
}
}





