ILookup与空集合

时间:2018-02-06 07:20:24

标签: c# linq dictionary

替换

是否存在固有的错误
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设计原则的事情。

Example

1 个答案:

答案 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中的性质。

您必须自己创建扩展方法。