我知道在实现自定义相等性检查时覆盖GetHashCode
的重要性 - 我已经实现了IEquality<T>
接口,以及泛型和非泛型Equals
{{3现在有意义覆盖Equals(object t)
吗?一切都不会归入通用Equals(T t)
吗?
public override int GetHashCode() //required for hashsets and dictionaries
{
return Id;
}
public bool Equals(T other) //IEquatable<T> here
{
return Id == other.Id;
}
public override bool Equals(object obj) //required??
{
return Equals(obj as T);
}
答案 0 :(得分:10)
未密封的类型不应该实现IEquatable<T>
,因为确保(甚至可能)派生类型将正确实现它的唯一方法是实现IEquatable<T>.Equals(T)
以便调用Object.Equals(Object)
}。由于IEquatable<T>
的全部目的是为了避免在比较它们之前浪费CPU时间将事物转换为Object
,因此调用Object.Equals(Object)
的实现无法比将要实现的默认行为更快地执行任何操作如果接口没有实现。
通过实施IEquatable<T>
,密封类类型可以获得轻微的性能优势;首选样式是让Object.Equals(Object)
尝试将参数强制转换为T
;如果演员成功,请使用IEquatable<T>.Equals
实现;否则返回false
。在传递相同的对象实例时,IEquatable.Equals(T)
和Object.Equals(Object)
不会产生不同的结果。
结构类型可以使用与密封类类型相同的模式。尝试强制转换的方法略有不同,因为失败的强制转换不能返回null
,但模式应该仍然相同。如果一个struct实现了一个变异接口(例如List<T>.Enumerator
,一个实现IEnumerator<T>
的结构)的情况,那么相等比较的正确行为有点模糊。
请注意,顺便说一句,IComparable<T>
和IEquatable<T>
应该被视为彼此独立。虽然通常情况是当X.CompareTo(Y)
为零时,X.Equals(Y)
将返回true,但某些类型可能具有自然顺序,其中两个事物可能不同而没有对另一个进行排名。例如,可能有一个NamedThing<T>
类型,它结合了string
和T
。这种类型支持名称的自然排序,但不一定支持T
。名称匹配但T
不同的两个实例应返回0
CompareTo
,false
Equals
。因此,如果IComparable
未更改,则覆盖GetHashCode
不需要覆盖Equals
。
答案 1 :(得分:6)
你肯定应覆盖Equals(object t)
- 否则在使用该重载时可能会得到错误的结果。你不能假设Equals(T other)
是要调用的重载。
如果不覆盖它,将使用引用相等性,这意味着类似下面的内容将返回false:
myObject1.Id = 1;
myObject2.Id = 1;
myObject1.Equals((object)myObject2); // false!
另一个可能的问题是继承类 - 如果将类型与继承类型进行比较,则很容易失败。
答案 2 :(得分:3)
来自msdn:
如果您实现IEquatable,您还应该覆盖基础 Object.Equals(Object)和GetHashCode的类实现 它们的行为与IEquatable.Equals的行为一致 方法。如果你覆盖了Object.Equals(Object),你的覆盖 在调用static时也会调用实现 在类上等于(System.Object,System.Object)方法。在 另外,你应该重载op_Equality和op_Inequality 运营商。这可确保所有相等的测试返回一致 结果
我本可以做一个更好的谷歌搜索。这是关于这个主题的good article on msdn blogs by JaredPar。
简而言之,覆盖Equals(object obj)
:
object 类上的静态 Equals(object obj1,object obj2)方法或 Contains(object item) on < em> ArrayList 实例等..
接受此项,因为该主题的链接更加彻底。感谢Oded ...