Метод одиночного расширения для IDictionary<K, IEnumerable / IList / ICollection <V >>

Я пытаюсь написать метод расширения, который будет конвертировать IDictionary<K, S<V>> проведение любого типа коллекции / последовательности (S<V>) чтобы ILookup<K, V> которая является более правильной структурой данных в этих случаях. Это означает, что я хотел бы, чтобы мое расширение работало на разных S типы и интерфейсы:

  • IDictionary<K, IEnumerable<V>>
  • IDictionary<K, ICollection<V>>
  • IDictionary<K, List<V>>

и т.д. В идеале я не хочу писать отдельную реализацию для каждого возможного типа коллекции И я хочу, чтобы вывод типа выполнял свою работу.

Что я пробовал это:

public static ILookup<TKey, TValue>ToLookup<TKey, TCollection, TValue>(
    this IDictionary<TKey, TCollection> dictionary)
        where TCollection : IEnumerable<TValue>

Но это не имеет TValue в списке параметров, поэтому вывод типа не может понять это - я получаю "Аргументы типа для метода ToLookup не могут быть выведены из использования".

Есть ли шанс, что это может работать как-то иначе, чем добавление подделки TValueпараметр для метода?

Примеры ожидаемого использования

Я надеюсь, что все вышеперечисленные вызовы будут возможны и приведут к вызову моего единственного метода расширения:

var dictOfIEnumerables = new Dictionary<int, IEnumerable<int>>();
var lookupFromIEnumerables = dictOfIEnumerables.ToLookup();

var dictOfICollections = new Dictionary<int, ICollection<int>>();
var lookupFromICollections = dictOfICollections.ToLookup();

var dictOfLists = new Dictionary<int, List<int>>();
var lookupFromLists = dictOfLists.ToLookup();

2 ответа

Решение

Потому что все коллекции реализуют IEnumerable<T>мы можем просто использовать его вместо TCollection Тип параметра. К сожалению, вывод типа не знает этого. Это код, который я написал:

public static ILookup<TKey, TValue> ToLookup<TKey, TValue>
        (this IDictionary<TKey, IEnumerable<TValue>> dict)
{
    return dict.SelectMany(p => p.Value.Select
        (v => new KeyValuePair<TKey, TValue>(p.Key, v)))
        .ToLookup(p => p.Key, p => p.Value);
}

Кажется, нет никакого способа заставить вывод типа работать, но этот метод будет работать, если вы приведете словарь:

((IDictionary<int, IEnumerable<int>>)dictOfLists).ToLookup()

Также вы можете добавлять списки в словарь IEnumerables и отбрасывать их обратно, когда они вам нужны.

После небольшого тестирования, которое я сделал, вот мои результаты.

Если я наберу dictOfIEnumerables.ToLookup(Вижу 4 перегруженных метода.

Однако, если я наберу dictOfIEnumerables.ToLookup<Вижу все 5 перегруженных методов.

Похоже, что вывод типа не работает из-за конфликта имен / разрешения между ToLookup(), который определен в IEnumerable. По-видимому, без угловых скобок это разрешает методы, определенные в IEnumerable, потому что это то, чем ограничивается TCollection. Может быть, кто-то в Stackru, который умнее меня, может объяснить вам, почему он работает так, как работает.

Тем не менее, использование указанных типов, на самом деле, работает правильно на моем компьютере.

Другие вопросы по тегам