我正在尝试编写一个扩展方法,将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();
答案 0 :(得分:1)
由于所有集合都实现了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的词典中,并在需要时将其强制转换。
答案 1 :(得分:0)
从我已经完成的测试中,我的结果如下。
如果我输入dictOfIEnumerables.ToLookup(
,我会看到4种重载方法
但是,如果我输入dictOfIEnumerables.ToLookup<
,我会看到所有5个重载方法。
由于在IEnumerable上定义的ToLookup()之间的名称冲突/解决冲突,似乎类型推断不起作用。显然,没有尖括号,它就会解析IEnumerable上定义的方法,因为这就是TCollection的限制。也许StackOverflow上的某个人比我更聪明,可以向你解释它为什么会这样运作。
但是,使用指定的类型确实可以在我的机器上正常工作。