如果我实现IEquatable ,重写Equals是否重要?

我知道在实现自定义相等性检查时重写GetHashCode的重要性 – 我已经实现了IEquality接口,以及此处讨论的generics和非genericsEquals之间的区别。 现在有一个重写Equals(object t)吗? 难道一切都不会归入通用Equals(T t)吗?

 public override int GetHashCode() //required for hashsets and dictionaries { return Id; } public bool Equals(T other) //IEquatable here { return Id == other.Id; } public override bool Equals(object obj) //required?? { return Equals(obj as T); } 

未密封的类型不应该实现IEquatable ,因为确保(甚至使其可能)派生类型将正确实现它的唯一方法是实现IEquatable.Equals(T)以便调用Object.Equals(Object) 。 由于IEquatable全部目的是为了避免在比较它们之前浪费CPU时间将事物转换为Object ,因此调用Object.Equals(Object)的实现无法比如果接口无法实现的默认行为更快地执行任何操作。没有实施。

通过实现IEquatable ,密封类类型可以获得轻微的性能优势; 首选的样式是让Object.Equals(Object)尝试将参数Object.Equals(Object)转换为T ; 如果转换成功,使用IEquatable.Equals实现; 否则返回false 。 在传递相同的对象实例时, IEquatable.Equals(T)Object.Equals(Object)在任何情况下都IEquatable.Equals(T)产生不同的结果。

结构类型可以使用与密封类类型相同的模式。 尝试强制转换的方法略有不同,因为失败的强制转换不能返回null ,但模式应该仍然相同。 如果结构实现了一个变异接口(例如List.Enumerator ,一个实现IEnumerator ),则相等比较的正确行为有点模糊。

注意,顺便说一句, IComparableIEquatable应该被认为是相互独立的。 虽然通常会出现这样的情况:当X.CompareTo(Y)为零时, X.Equals(Y)将返回true,某些类型可能具有自然顺序,其中两个事物可能不同,而不会对另一个进行排名。 例如,可能有一个NamedThing类型,它组合了一个string和一个T 这种类型将支持名称的自然排序,但不一定支持T 名称匹配但其T不同的两个实例应为CompareTo返回0 ,但对于Equals返回false 。 因此,如果未更改Equals ,则覆盖IComparable不需要覆盖GetHashCode

您当然应该重写Equals(object t) – 否则在使用该重载时可能会得到不正确的结果。 你不能假设Equals(T other)是要调用的重载。

如果不覆盖它,将使用引用相等性,这意味着类似以下内容将返回false:

 myObject1.Id = 1; myObject2.Id = 1; myObject1.Equals((object)myObject2); // false! 

另一个可能的问题是inheritance类 – 如果将类型与inheritance类型进行比较,则很容易失败。

来自msdn :

如果实现IEquatable,还应该覆盖Object.Equals(Object)和GetHashCode的基类实现,以使它们的行为与IEquatable.Equals方法的行为一致。 如果您重写了Object.Equals(Object),则在对类的静态Equals(System.Object,System.Object)方法的调用中也会调用重写的实现。 此外,您应该重载op_Equality和op_Inequality运算符。 这可确保所有相等测试都返回一致的结果。

我本可以做一个更好的谷歌搜索。 这是JaredPar关于这个主题的msdn博客上的一篇很好的文章 。

简而言之,重写Equals(object obj)

需要对象类的静态Equals(对象obj1,对象obj2)方法,或ArrayList实例上的Contains(对象项)等。

接受这一点,因为该主题的链接更加彻底。 感谢Oded …