Вы смешали ковариацию и контравариантность.
При ковариации аргумент универсального типа может быть «меньше», чем требуется. То есть если у нас есть:
Func<Mammal, Mammal> f1 = whatever;
Func<Mammal, Animal> f2 = f1;
Почему это работает? Func
- ковариант во втором параметре. f2
ожидает делегата, который возвращает Animal
. У него есть делегат, который возвращает меньший тип; количество Mammal
с меньше Animal
с, поэтому Mammal
меньше .
Подумайте, почему это работает. Когда кто-то звонит f2, он ожидает вернуть животное. Но если они действительно называют f1, они все равно получают животное, потому что каждое млекопитающее является животным.
При ковариации «размер» универсального типа изменяется в том же направлении , что и размер аргумента типа. Mammal
меньше Animal
. Func<Mammal, Mammal>
меньше Func<Mammal, Animal>
. Вот почему это «co» дисперсия, co означает «вместе».
Контравариантность - это противоположность, следовательно, "против", что означает "против". В отличие от этого аргумент универсального типа может быть больше ожидаемого:
Func<Giraffe, Mammal> f3 = f1;
f3 ожидает функцию, которая принимает жирафа; у нас есть функция, которая принимает более крупного типа, млекопитающее. Это больше, потому что там больше млекопитающих, чем жирафов. Contravariance говорит, что это хорошо, и это должно иметь смысл. Если кто-то вызывает f3 с жирафом, то это нормально, если это на самом деле вызов f2, потому что f2 может взять жирафа; это может принять любое млекопитающее.
Вы смешали ковариацию и контравариантность; вы ожидаете, что контравариантный параметр можно использовать ковариантным образом, что неверно. Функция, которая принимает сотрудников, не может быть преобразована в функцию, которая принимает людей, поскольку вы можете передать ей сотрудника, не являющегося сотрудником. Функция, которая принимает сотрудников, может быть преобразована в функцию, которая принимает менеджеров, потому что все менеджеры являются сотрудниками.