为什么Enumerable.SequenceEqual如果任何参数为null则抛出异常?

时间:2011-06-20 05:45:20

标签: c# linq

我正在尝试使用Enumerable.SequenceEqual(x,y),因为我预计它会在此基础上发挥作用 Object.Equals(x,y)方法,如果x或y为null,则返回false;如果两者都为null,则返回true(对于null情况)。

但是,Enumerable.SequenceEqual(x,y)如果任何参数是空引用则抛出异常,如果给出两个空值则不返回true。

在我的代码中,我经常检查集合相等性,所以我创建了一个模拟序列Object.Equals行为的方法,但我只是想知道这种默认行为背后的逻辑是什么,并且可能存在一个没有例外的现有方法在nulls?

2 个答案:

答案 0 :(得分:4)

好吧,MSDN documentation明确声明它会抛出一个ArgumentNullException,以防任何一个传入的序列为空。我认为这是为了保持与“标准行为”的一致性,当你试图取消引用它时,一个对象抛出NullReferenceException。考虑一下:

 List<int> foo = null;
 foo.SequenceEqual(new List<int>());

这是可以的,因为SequenceEqual是一个扩展方法,因此可以处理一个空对象,但也会让人感到困惑。据我所知,Linq提供的每种扩展方法都遵循这种行为。此外,您不需要为每个扩展方法处理特殊的null情况(您需要同意合理的行为并添加其他逻辑并维护和测试它)。从框架的角度来看,它说它是非法的,使其更加健壮(针对逻辑错误)并保持一致。我经常使用Linq并且从未遇到过这个问题 - 我只是确保我的所有序列都不为空。减少代码混乱(从代码中删除大量空值检查)。

答案 1 :(得分:2)

检查序列相等性的时间点不是在抛出异常时。它作为参数验证器被提前抛出。考虑方法:

public static bool SequenceEquals<T>(this IEnumerable<T> source, IEnumerable<T> target)
{
    // Stuff
}

我们明确需要检查sourcetarget是否为空,因为如果其中任何一个是,那么我们不能检查序列是否相等。这是一个不可行的状态,SequenceEquals的结果应该由可枚举的内容控制,而不是可枚举的状态。如果要包含后者,当返回false时,调用者将如何知道它是否实际上是因为序列不相等而失败,或者一个或两个可枚举是null

如果我们没有在这里抛出ArgumentNullException,当您尝试访问其中一个NullReferenceException枚举时,CLR会抛出null。简单地说Object reference not set to an instance of an objectThe argument <something> cannot be null更有帮助。

请记住,抛出的异常类型通常是关于为什么抛出异常的最有用指标之一。