26

我有一个包含 Find 方法的自定义通用数据结构:

public bool Find(TValue value, IEqualityComparer<TValue> comparer)
{
    foreach (var x in items)
    {
        if (comparer.Equals(value, x))
            return true;
    }
    return false;
}

我最近从一位客户那里得到了一份报告,他说这会导致他的相等比较器抛出NullReferenceExceptionif valueisnull或如果集合中的一个项目 is null

我最初的反应是他的IEqualityComparer<T>.Equals实现是错误的,因为它没有优雅地处理null值。但是我找不到任何文件来明确支持我。我有一些证据表明我是对的,但没有明确的证据。

首先,我将这个简单的调用更改comparer.Equals为:

if (x == null)
{
    if (value == null)
        return true;
}
else if (value != null && comparer.Equals(value, x))
    return true;

其次,Object.Equals的文档除其他外说:

  • x.Equals(null)返回false
  • 的实现Equals不得抛出异常。

对我来说,这有力地证明了IEqualityComparer<T>.Equals应该优雅地处理空参数。

其他证据是IComparer.Compare的文档说:

允许将 null 与任何引用类型进行比较,并且不会产生异常。空引用被认为小于任何非空引用。

人们会期望IEqualityComparer<T>.Equals采取类似的行动。不过,有趣的是,NullReferenceException如果任一参数为null.

我浏览了 、 、 和 的文档Object.Equals以及IEquatable<T>无数IEqualityComparer<T>IEqualityComparer博客文章、文章和 SO 问题。没有任何关于如何处理null参数的具体指导。

有这样的指导方针吗?如果没有,大师们有什么建议,为什么?

4

4 回答 4

26

.NET 框架本身中最接近的方法IEqualityComparer.Equals是静态方法,所有方法都应在该方法之后建模Object.Equals(object,object)。根据文档,此方法可以null优雅地处理 s。我认为这为 .NET 设计者的意图提供了足够的指示:IEqualityComparer.Equals也应该处理空值,并且应该以类似的方式处理它们(即,将两个nulls 视为彼此相等)。

于 2012-12-12T02:25:26.037 回答
2

FxCop 使用的准则包括一项规定,即公共类型的每个公共方法都必须处理空参数,例如通过抛出ArgumentNullException. 在您的情况下,鉴于Object.Equals您指出,那么您只需要进行 null 测试并返回 false - 因为只有 null 等于 null :)

这记录在这里:http: //msdn.microsoft.com/en-us/library/ms182182 (v=VS.80).aspx

于 2012-12-12T02:17:25.640 回答
1

好吧,EqualityComparer<T>抽象基类(不是接口,但确实实现了它)对其Equals方法有一些注释。

因为EqualityComparer<T>.Equals(T, T)MSDN 没有说明通常会抛出任何已知的异常(而且 MSDN 通常非常擅长列出异常)。当然,传入任何类(自定义或 BCL)并将其与它进行比较null不会引发任何异常。

http://msdn.microsoft.com/en-us/library/ms132154.aspx

于 2012-12-12T02:40:13.603 回答
1

的值null应被视为任何其他值。如果你被问到两个盒子的内容是否应该被认为是相同的,即使其中一个或两个盒子都是空的,这个问题也是完全有效的。如果两个盒子都是空的,它们的(非)内容是相等的。如果一个是空的而另一个不是,那么它们显然不是完全等价的,并且可能不会比较相等,但在某些情况下它们是合法的。

Object.Equals(Object)由and定义的默认等价关系IEquatable<T>.Equals(T)(如果定义了后者,则应使用与前者相同的关系)仅当事物基本上在所有方面都相等时才应将其视为相等,并且根据该定义,没有非空对象可以被认为等同于 null(因为null无法将自身与非 null 对象进行比较)。另一方面,将 的IEqualityComparer<T>两个实例定义为就其目的而言T是等价的,这是完全正常的,即使它们明显不相同,特别是如果在每个实例上调用的某个函数会产生相同的值。如果所讨论的函数被视为合法值,那么函数返回的值与它返回的值相同的非空值nullnull应该比较等于null

于 2012-12-15T21:18:51.777 回答