我有一个包含Find方法的自定义通用数据结构:
public bool Find(TValue value, IEqualityComparer<TValue> comparer)
{
foreach (var x in items)
{
if (comparer.Equals(value, x))
return true;
}
return false;
}
我最近收到了一位客户的报告,他说如果NullReferenceException
为value
,或者集合中的某个项目为{{{}},则会导致他的等式比较器抛出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
。
我浏览过null
,Object.Equals
,IEquatable<T>
和IEqualityComparer<T>
的文档,以及无数博客文章,文章和SO问题。没有任何关于如何处理IEqualityComparer
参数的具体指导。
是否存在此类指南?如果没有,大师会推荐什么,以及为什么?
答案 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
进行比较并不会产生任何异常。
答案 3 :(得分:1)
值null
应视为任何其他值。如果询问您是否认为两个方框的内容相同,即使其中一个或两个方框为空,问题也完全有效。如果两个框都为空,则它们的(非)内容相等。如果一个是空的而另一个不是,那么它们显然不是完全等价的,可能不会相等,但有些情况下它们是合法的。
由Object.Equals(Object)
和IEquatable<T>.Equals(T)
定义的默认等价关系(后者,如果定义,应该使用与前者相同的关系)应该只考虑事物是否相等如果它们基本上是相同的方式,并且通过该定义,不能将非null对象视为等效于null(因为null
无法将自身与非null对象进行比较)。另一方面,IEqualityComparer<T>
将T
的两个实例定义为等效用于其目的是完全正常的,即使它们明显不相同,尤其是在每个函数上调用的某个函数将产生相同的值。如果有问题的函数将null
视为合法值,则函数返回与null
相同的值的非空值应该等于null
。