替换
是否存在固有的错误IDictionary<int, IEnumerable<string>>
与
ILookup<int, string>
我更喜欢ILookup而不是IDictionary,因为它更“诚实”的界面和不变性。
但是,我发现ILookup无法保存空集合,因此包含空集合的密钥根本就不存在。这是问题,因为我也希望ILookup传达有关所有可能键的信息(即使其中一些可能是空的),所以我可以这样:
var statistics = from grouping in myLookup
select new {grouping.Key, grouping.Count()};
与enumerables字典一起使用,但遗憾的是不适用于ILookup。与IDictionary一样,grouping.Count()== 0的条目是不可能的。 正如John Skeet所说,
查找和字典之间还有另外一个重要的区别:如果要求查找与其不知道的键对应的序列,它将返回一个空序列,而不是抛出异常。 (查找确实知道的密钥永远不会产生空序列。)
现在,如果ILookup允许空分组,会出现什么问题?为了充分利用这两个世界,我即将为ILookup添加Filter()扩展方法,但是需要解决Linq不允许创建空IGroupings的问题(所以我必须实现自己的类) ),但我觉得我可能正在做一些违反Linq设计原则的事情。
答案 0 :(得分:0)
两个选项:
1)你可以创建一个漂亮,直截了当的单例式EmptyLookup类,如下所示:
var empty = EmptyLookup<int, string>.Instance;
// ...
public static class EmptyLookup<TKey, TElement>
{
private static readonly ILookup<TKey, TElement> _instance
= Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
public static ILookup<TKey, TElement> Instance
{
get { return _instance; }
}
}
2)您可以为空查找创建单例类。
public sealed class EmptyLookup<T, K> : ILookup<T, K>
{
private static readonly EmptyLookup<T, K> _instance
= new EmptyLookup<T, K>();
public static EmptyLookup<T, K> Instance
{
get { return _instance; }
}
private EmptyLookup() { }
public bool Contains(T key)
{
return false;
}
public int Count
{
get { return 0; }
}
public IEnumerable<K> this[T key]
{
get { return Enumerable.Empty<K>(); }
}
public IEnumerator<IGrouping<T, K>> GetEnumerator()
{
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
yield break;
}
}
then you can write code like this:
var x = EmptyLookup<int, int>.Instance;
/*The benefit of creating a new class is that you can use the "is" operator and check for type equality:*/
if (x is EmptyLookup<,>) {
// ....
}
保持空分组是查找没有错,只是查找不支持它,因为它在Linq中的性质。
您必须自己创建扩展方法。