Подтвердить что ты не робот

Должен ли ILookup <TKey, TElement> быть (объявлен) ковариантным в TElement?

Определение System.Linq.ILookUp читает

interface ILookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>>, IEnumerable {
    int Count {
        get;
    }

    IEnumerable<TElement> this[TKey key] {
        get;
    }

    bool Contains(TKey key);
}

Поскольку IEnumerable является ковариантным в IGrouping < TKey, TElement > , IGrouping < TKey, TElement > является ковариантным в TElement, и интерфейс только предоставляет TElement в качестве возвращаемого типа, я бы предположил, что ILookup также ковариантен в TElement. Действительно, определение

interface IMyLookup<TKey, out TElement> : IEnumerable<IGrouping<TKey, TElement>>, IEnumerable {
    int Count {
        get;
    }

    IEnumerable<TElement> this[TKey key] {
        get;
    }

    bool Contains(TKey key);
}

компилируется без проблем.

Итак, какова может быть причина, по которой ключевое слово out отсутствует в исходном определении? Можно ли добавить будущие версии Linq?

4b9b3361

Ответ 1

Отслеживание документации MSDN, Ковариация и контравариантность в общих целях были внедрены в .NET Framework 4 До этого было IEnumerable<T> с тех пор .NET Framework 2.0 до .NET Framework 3.5. Затем в .NET Framework 4.0 мы можем видеть IEnumerable<out T> с параметром типа T как ковариацией.

IGrouping<TKey, TElement> и ILookup<TKey, TElement> существуют с .NET Framework 3.5. В .NET Framework 4.0 первая была обновлена ​​до IGrouping<out TKey, out TElement>, но последняя была опущена без указания причины.

TKey не может быть ковариантным, поскольку реализации Contains(TKey) и this[TKey] предотвращают это.

Что касается TElement, вопрос не ясен. Я не верю, что дизайнеры просто пропустили это. Возможно, причина лежит в планах на будущее. Или они хотели предотвратить что-то вроде ниже, но я не знаю, почему:

string[] strings = new[] {"a", "a", "b", "b", "b", "c"};
ILookup<string, string> lookup = strings.ToLookup(s => s); // Valid.
ILookup<string, object> lookup = strings.ToLookup(s => s); // Now invalid, but would correct if TElement was covariant (out TElement).

Есть и другие авторы, которые обращают внимание на эту проблему:

ToLookup:

Следует отметить, что хотя IGrouping является ковариантным в TKey и TElement, ILookup инвариантен в обоих параметрах своего типа. Хотя TKey должен быть инвариантным, было бы разумно, чтобы TElement был ковариантным