Ковариантность и контрвариантность

Что означает ковариантность и контрвариантность?

Ковариантность означает, что мы можем использовать более конкретные типы, чем были указаны изначально. По этой теме давайте рассмотрим следующий пример:

IList objects = new MyList(); // можете проверить, компилятор ругаться не будет

Инвариантность означает, что ковариантность и контрвариантность недопустимы. Использовать можно только тот тип, которым мы закрыли наш объект (например, список). Использование других типов строго запрещены, даже если они прямо идут по иерархии наследования от класса, которым закрыт объект. Пример:

List objects = new MyList(); // вот здесь компилятор откровенно будет ругаться

Контрвариантность - это полная противоположность коварантности. Идея контрвариантности заключается в том, что можно использовать общие типы вместо конкретных. ОБЩИЕ вместо КОНКРЕТНЫХ. Да, это звучит тупо...

interface IInterfacable where T : BaseClass
{
void Push(T obj); // в данном примере ошибки не будет, если перед T вставить ключевое слово in
}

static void Main(string[] args)
{
IInterfacable arr = new Stack();
}