【问题标题】:Is C# SortedList<TKey, TValue>.Keys.Contains method throwing a null exception a good thing?C# SortedList<TKey, TValue>.Keys.Contains 方法抛出空异常是件好事吗?
【发布时间】:2016-06-30 20:12:44
【问题描述】:

考虑这段代码(也可以使用in Ideone):

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        Console.WriteLine(HasItem(new List<string>(), null));
        try {
            Console.WriteLine(HasItem(new SortedList<string, int>().Keys, null));
        } catch (ArgumentNullException) {
            Console.WriteLine("ArgumentNullException");
        }
    }

    public static bool HasItem(ICollection<string> collection, string item) {
        return collection.Contains(item);
    }
}

问题

输出是

错误

ArgumentNullException

在深入了解SortedList&lt;TKey, TValue&gt; 的工作原理后,我发现此调用等效于调用SortedList&lt;TKey, TValue&gt;.ContainsKey(TKey key) 方法,该方法记录了ArgumentNullException

另一方面,ICollection&lt;T&gt;.Contains 方法的文档指出:

如果在ICollection&lt;T&gt; 中找到项目,则返回:true;否则,false

好吧,null 在我的示例中不是第二个集合的一部分,所以我希望返回 falseArgumentNullException 违反了接口,因此是一个错误。

生产代码中的解决方法是什么?鉴于.Keys 属性返回私有通用嵌套类的实例,类型检查将非常难看,而我没有任何其他想法。另外,类型检查是一种非常讨厌的代码气味。

【问题讨论】:

  • 我想有你的问题:-)
  • > 生产代码中的解决方法是什么?也有点讨厌,但是捕获异常并返回false
  • @Jay 谢谢你,是的,这是一种可能,但它太宽泛了,不幸的是——我只想处理SortedList 的情况
  • catch (ArgumentNullException) { return false; }?我知道,它也很丑。
  • 我实际上会说包含实现是错误的,因为它应该查看值而不是键。话虽如此 - 它就是这样,它不会改变所以代码围绕它

标签: c# specifications sortedlist


【解决方案1】:

SortedList 类实现了IDictionary,它指定了SortedListKey, value 性质。由于IDictionary 实现的预期工作方式(使用哈希码对键进行排序或索引),您不能输入null 对象作为键,因为null 没有有效的哈希码。出于这个原因,Contains(...) 方法将在尝试将null 传递到参数时抛出ArguementInvalidException,因为它知道null 不是有效的键。

如果您想为生产环境“修复”此问题(我不建议这样做,因为这应该不是问题),我建议扩展 SortedList 类并覆盖 Contains(...) 方法通过null 争论后安全返回。

【讨论】:

  • 没错,但这也与最初的问题相去甚远。是的,SortedList 是字典,好吧,但我们在这里讨论的是 SortedList.Keys,它不是字典 - 它只是一个集合。
  • 另外,我只能访问HasItem方法,Main方法是消费者定义的代码
  • 哦,不过看来还是在同一条船上。 MSDN doc 声明不同的Contains 方法将使用最适合父对象性质的任何实现(它也明确提到IDictionary。)但是,Keys 属性似乎很可能实现@987654343 @ 的行为方式应该类似于List,但它的行为可能更像它的父对象IDictionary。当然,它最终也可能只是一个 .NET 怪癖。
【解决方案2】:

我在 MSDN 上找到了这一行:Type: T 要在集合中定位的对象。对于引用类型,该值可以为 null。

编辑:您需要 System.Linq 的 using 语句

使用 System.Linq;

       SortedList<string, int> temp = new SortedList<string, int>();
        bool test = HasItem(temp.Keys, null);


    public bool HasItem(ICollection<string> collection, object item)
    {
        return collection.Contains(item);
    }//This returns false when fed a null

我认为通过使用 Object 作为我的参数而不是不可变的字符串,我的参数真正被识别为引用类型。无论哪种方式,此功能都已经过测试并且可以正常工作。祝你好运。

【讨论】:

  • 你是如何编译的? ICollection&lt;T&gt; 没有 Contains(object value) 方法声明
  • 我不确定你的意思,但我在 Visual Studio 2015 的 asp.net MVC 中运行我的代码。我的框架是 4.5。您是否在同一个目标框架上运行,这应该是在这种情况下唯一重要的事情。它编译没有错误。
  • 如您所见here,在这个界面中没有这样的方法。您100% 确定您的环境中没有为您提供任何扩展方法吗?
  • 好的,我开始隔离代码,看来您需要一个 using 语句,而仅使用 System; 是无法做到的。使用 System.Collections.Generic;您还必须包括 System.Linq。但就扩展而言,我写了很多,但还没有为此写一个。
  • 虽然这确实解决了this very example中抛出的异常,但代码走的是完全不同的路径。如果用户有一个他传递给HasItem 方法的ICollection&lt;T&gt; 的自定义实现怎么办?您提出的方法不会通过这种自定义逻辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多