.NET поддерживает ковариацию в интерфейсах, делегатах, универсальных типах и массивах. Интерфейс или тип должен указывать его ковариантно, хотя с ключевым словом out
.
Вы можете написать
IEnumerable<Animal> animals=new List<Flea>();
или
var dict=new Dictionary<int,Flea>{
[1]=new Flea()
};
IEnumerable<Animal> animals=dict.Values;
Это работает, потому что Dictionary.Values
возвращает IEnumerable<Flea>
, а IEnumerable является ковариантным - его определение IEnumerable<out T>
.
KeyValuePair хотя и не является ковариантным, что означает, что классы, использующие его, такие как IDictionary<TKey,TValue>
и IReadOnlyDictionary<TKey,TValue>
, также не являются. Это было преднамеренно.
Поскольку вам нужно только прочитать из этого словаря, вы можете создать метод доступа с помощью делегата или, в C # 7 и более поздних версиях, локальной функции. Вы можете передать эту функцию методам, ожидающим Func<TKey,TValue>
, и использовать ее для чтения значений из словаря.
Если у вас есть метод, который требует доступа на основе ключей, скажем:
void Process(Func<int,Animal> reader)
{
var value=reader(1);
}
В C # 7 вы можете написать:
var dict =...
Animal get(int key)=>dict[key];
Process(get);
Это немного обманывает, используя переменную перехват для доступа к словарю.
До C # 7 вы использовали делегата:
Func<int,Animal> get= key=>dict[key];
Process(get);
Это может показаться странным, но именно так работает LINQ , используя предикаты и делегаты вместо интерфейсов и оболочек.