【问题标题】:ILookup with empty collections带有空集合的 ILookup
【发布时间】:2018-02-06 07:20:24
【问题描述】:

替换有什么固有的错误

IDictionary<int, IEnumerable<string>>

ILookup<int, string>

我更喜欢 ILookup 而不是 IDictionary,因为它更“诚实”的界面和不变性。

但是,我发现 ILookup 无法保存空集合,因此包含空集合的键根本不存在。这是个问题,因为我还希望 ILookup 传达有关所有可能键的信息(即使其中一些可能是空的),所以我可以这样:

var statistics = from grouping in myLookup
                 select new {grouping.Key, grouping.Count()};

它适用于可枚举字典,但不幸的是不适用于 ILookup。与 IDictionary 一样,不可能有 grouping.Count()==0 的条目。 正如约翰斯基特所说,

查找和字典之间还有一个重要区别:如果您要求查找与它不知道的键对应的序列,它将返回一个空序列,而不是抛出异常。 (查找确实知道的键永远不会产生空序列。)

现在,如果 ILookup 允许空分组有什么问题?为了两全其美,我将为 ILookup 添加 Filter() 扩展方法,它就是这样做的,但需要解决 Linq 不允许创建空 IGroupings 的问题(所以我必须实现我自己的类),但我觉得也许我在做一些违反 Linq 设计原则的事情。

Example

【问题讨论】:

  • 如果您能提供minimal reproducible example 重现您要解决的问题,那就太好了。
  • I much prefer ILookup over Dictionary because of its more 'honest' interface and immutability. 一个是接口,另一个是实际类。这不是更诚实,如果你想要一个不可变的字典,请使用 ImmutableDictionaryReadOnlyDictionary
  • @PanagiotisKanavos 我确定他的意思是写IDictionary 而不是Dictionary
  • ILookup 无论如何都是一个专用接口。 ILookup&lt;int, string&gt; IEnumerable&lt;IGrouping&lt;int, string>>`。没有分组,没有条目。这意味着持有一个空集合,即没有分组,与界面本身相矛盾
  • @UweKeim 并没有改变 ILookup 只是一个接口,其实现对最终用户不透明,并且 IDictionary。即使与 IReadOnlyDictionary 相比,它们也有非常不同的语义

标签: c# linq dictionary


【解决方案1】:

两个选项:

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

你必须自己创建一个扩展方法。

【讨论】:

  • 空查找不是我的意图,而是允许在某些键下进行空集合的查找。是的,我知道如果键不存在,ILookup 会返回空序列,但我也想枚举 Lookup 中存在的所有现有键条目,但其中一些可能为空
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 2013-05-27
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 1970-01-01
相关资源
最近更新 更多