Object-oriented programming allows types to be substituted in some scenarios. For example, if a method takes a Account
it is fine to pass in an instance of the subclass SavingsAccount
.
This is known as Contravariance and has been supported since C# 1.0. Generic contravariance brings this to generics!
Let us consider IList<T>
. We can never assign anything implementing this interface to IList<SubOfT>
because it both accepts arguments of T
(Add
) and returns T
(for Get
). No type except T
can be both a subclass and a superclass.
But what about a interface that only accepts T
and does something with it like a message sender? Using generic contravariance solves this problem.
Code
C#
ISender<MyMessage> sender = getSender(); // Is actually Sender<Message>
sender.Send(new MyMessage());
...
interface ISender<out T> { ... }
C#
// Can't constrain this to MyMessage without creating a new sender
ISender<Message> sender = getSender(); // Is actually Sender<Message>
sender.Send(new MyMessage());
...
interface ISender<T> { ... }
Notes
- It's easier to start by understanding Generic covariance C# 4.0 first