【问题标题】:Empty ILookup<K, T>空 ILookup<K, T>
【发布时间】:2011-07-25 19:46:12
【问题描述】:

我有一个返回ILookup 的方法。在某些情况下,我想返回一个空的ILookup 作为提前退出。构造一个空的ILookup 的最佳方法是什么?

【问题讨论】:

  • 您在 ILookup 中使用哪些类型作为 K 和 T?

标签: c# .net ilookup


【解决方案1】:

除了mquanderVasile Bujac 的答案之外,您可以创建一个漂亮、直接的单例EmptyLookup&lt;K,E&gt; 类,如下所示。 (在我看来,按照 Vasile 的回答创建完整的 ILookup&lt;K,E&gt; 实现似乎没有多大好处。)

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; }
    }
}

【讨论】:

  • 感谢 mquander 和 Vasile,但我认为这两种解决方案的合并是最简单/最好的。
【解决方案2】:

没有内置的,所以我只需要编写一个扩展方法来运行类似于new T[0].ToLookup&lt;K, T&gt;(x =&gt; default(K)); 的东西

强烈怀疑在这里返回 null 会更正确。几乎从不希望从返回集合(而不是空集合)的方法中返回 null。我完全不同意那些建议的人。

【讨论】:

  • 需要考虑返回值的语义。例如,不返回结果的搜索应返回空集合,但(例如)失败或具有无效参数的搜索应返回 null
  • 好吧,一个包含无效参数的搜索(如,我认为方法的无效参数)可能应该抛出。但我理解你的意思。但是,一个方法返回一个空集合当然很常见,在这种情况下返回 null 通常是一团糟。
  • 关于抛出错误,您确实是正确的。但是,我曾使用过业务应用程序,例如,某些外部系统在一天中的某些时间会变得不可用;在这种情况下,查询和请求会失败,但这不是“例外”情况,因为它是预期的行为。
  • @mquander - 完全同意 null。空的东西几乎总是更好的选择。
  • 我同意抛出而不是返回 null - 抛出一个有用的异常(不要剥离信息!)并为自己省去未来运行时调试的麻烦。
【解决方案3】:

您可以为空查找创建一个单例类。

using System.Linq;

public sealed class EmptyLookup<T, K> : ILookup<T, K> 
{
        public static readonly EmptyLookup<T, K> Instance { get; }
            = new EmptyLookup<T, K>();

        private EmptyLookup() { }

        public bool Contains(T key) => false;

        public int Count => 0;

        public IEnumerable<K> this[T key] => Enumerable.Empty<K>();

        public IEnumerator<IGrouping<T, K>> GetEnumerator()
          => Enumerable.Empty<IGrouping<K, V>>().GetEnumerator();

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 }

那么你可以这样写代码:

var x = EmptyLookup<int, int>.Instance;

创建新类的好处是可以使用“is”运算符并检查类型是否相等:

if (x is EmptyLookup<,>) {
 // ....
}

【讨论】:

  • 严格来说,这可能是最好的答案。
  • 谢谢,看起来不错。我建议 [] 应该抛出 KeyNotFoundException 而不是 NotImplementedException。
  • 实际上Lookup&lt;K, V&gt;的.NET实现如果在集合中找不到key,则返回一个空序列
【解决方案4】:

基于LukeH 的答案,我将使用Empty&lt;TKey, TElement&gt; 方法创建一个静态类Lookup。这种方式你可以使用的方式和Enumerable.Empty&lt;T&gt;一样。

public static class Lookup
{
    public static ILookup<TKey, TElement> Empty<TKey, TElement>()
        => Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
}

示例用法:Lookup.Empty&lt;string, string&gt;()

【讨论】:

【解决方案5】:

创建一个空列表,然后对其执行 ToLookup(),如下所示:

List<Point> items = new List<Point>();
ILookup<int, int> lookup = items.ToLookup(p => p.X, p => p.Y);

祝你好运!

【讨论】:

    【解决方案6】:

    感谢@mqp 的好主意。我可以基于该方法提出几种扩展方法:

    public static class IEnumerableExtensions
    {
        public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IEnumerable<TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
        public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IDictionary<TKey, TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
        public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IGrouping<TKey, TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
        public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IEnumerable<ILookup<TKey, TElement>> elements) => new TElement[0].ToLookup(k => default(TKey));
    }
    

    【讨论】:

      【解决方案7】:

      或者更符合 LINQ 精神的东西:

          public static class Utility
      {
      
          public static ILookup<TKey, TElement> EmptyLookup<TKey, TElement>(Func<TKey, TKey> keySelector,
                                                                            Func<TKey, TElement> elementSelector)
          {
              return Enumerable.Empty<TKey>().ToLookup(keySelector, elementSelector);
          }
      
      }
      

      【讨论】:

      • 为什么还要费心接受选择器功能?
      【解决方案8】:

      你可以返回 null

      或异常

      但你应该在课堂评论中注明

      补充:+这比一些扩展方法更明显

      【讨论】:

      • 我完全不同意。如果一个函数返回一个查找映射一些Ks 到Ts,并且碰巧没有Ks 或Ts,那么很明显该函数应该返回一个空查找。返回 null 或抛出异常是没有任何意义的,并且突然不得不到处检查它,如果你返回一个空的查找,它就会开箱即用。
      • "ILookup 作为提前退出" - 这是您应该抛出异常的典型情况。
      • 如果您对异常发表评论,所有其他开发人员都会在样式中看到它。并处理该异常。
      • + 这比一些扩展方法更明显
      • 我同意 mquander 的观点,如果一个函数返回一个集合/映射类型,那么“无项目”应该转换为空实例而不是 null。当我说提前退出时,我的意思是检查了一个初始条件,它发现该方法没有工作要做,所以我只想返回任何内容/空。
      猜你喜欢
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-02
      • 2022-01-21
      相关资源
      最近更新 更多