IEqualityComparer.Equals的实现是否应允许空值?

时间:2012-12-12 02:12:59

标签: c# generics equality

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

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

我最近收到了一位客户的报告,他说如果NullReferenceExceptionvalue,或者集合中的某个项目为{{{}},则会导致他的等式比较器抛出null 1}}。

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

首先,我将null的简单调用改为:

似乎很愚蠢
comparer.Equals

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

  • if (x == null) { if (value == null) return true; } else if (value != null && comparer.Equals(value, x)) return true; 返回x.Equals(null)
  • false的实现不得抛出异常。

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

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

  

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

人们会期望Equals采取类似行动。但是,有趣的是,如果任一参数为IEqualityComparer<T>.Equals,则该页面上给出的示例将抛出NullReferenceException

我浏览过nullObject.EqualsIEquatable<T>IEqualityComparer<T>的文档,以及无数博客文章,文章和SO问题。没有任何关于如何处理IEqualityComparer参数的具体指导。

是否存在此类指南?如果没有,大师会推荐什么,以及为什么?

4 个答案:

答案 0 :(得分:24)

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

答案 1 :(得分:2)

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

此处记录了这些内容:http://msdn.microsoft.com/en-us/library/ms182182(v=VS.80).aspx

答案 2 :(得分:1)

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

对于EqualityComparer<T>.Equals(T, T),MSDN没有声明任何已知的异常通常被抛出(并且MSDN通常非常适合列出异常)。当然传入任何类(自定义或BCL)并将其与null进行比较并不会产生任何异常。

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

答案 3 :(得分:1)

null应视为任何其他值。如果询问您是否认为两个方框的内容相同,即使其中一个或两个方框为空,问题也完全有效。如果两个框都为空,则它们的(非)内容相等。如果一个是空的而另一个不是,那么它们显然不是完全等价的,可能不会相等,但有些情况下它们是合法的。

Object.Equals(Object)IEquatable<T>.Equals(T)定义的默认等价关系(后者,如果定义,应该使用与前者相同的关系)应该只考虑事物是否相等如果它们基本上是相同的方式,并且通过该定义,不能将非null对象视为等效于null(因为null无法将自身与非null对象进行比较)。另一方面,IEqualityComparer<T>T的两个实例定义为等效用于其目的是完全正常的,即使它们明显不相同,尤其是在每个函数上调用的某个函数将产生相同的值。如果有问题的函数将null视为合法值,则函数返回与null相同的值的非空值应该等于null