警告:";..重写Object.Equals(Object o),但不重写Object.GetHashCode(
本文关键字:Object 重写 GetHashCode Equals quot 警告 | 更新日期: 2023-09-27 18:00:11
我重写类的Equals()以比较Guid类型的ID值。
然后Visual Studio发出警告:
覆盖Object.Equals(对象o),但是不覆盖Object.GetHashCode()
因此,我还重写了它的GetHashCode(),如下所示:
public partial class SomeClass
{
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || this.GetType() != obj.GetType()) return false;
return this.Id == ((SomeClass)obj).Id;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
这似乎奏效了我做对了吗记住Id的类型为Guid我的类是实体框架对象有关系吗
正如其他人所说,在Equals中使用反射似乎是不可靠的。抛开这些不谈,让我们集中讨论GetHashCode。
不能违反的GetHashCode的主要规则是如果两个对象相等,则它们必须具有相同的哈希代码。或者,一种等效的说法是如果两个对象有不同的哈希码,那么它们一定是不相等的您的实现看起来不错。
你可以违反相反的规定。也就是说,如果两个对象具有相同的哈希代码,则允许它们相等或不相等,正如您所认为的那样。
我假设"Id"是一个不可变的属性。如果"Id"可以在对象的生存期内更改,那么在将对象放入哈希表时可能会出现问题。考虑确保在计算等式和哈希代码时只使用不可变的属性。
您的实现看起来不错,但您提出这个问题的事实表明,您可能还没有完全掌握构建GetHashCode实现的所有微妙因素。一个好的开始是我的文章主题:
http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
这对我来说是正确的。每当我做这样的事情时,我通常还会实现IEquatable
,这样同一编译时类型的变量之间的比较就会更加有效。
public partial class SomeClass : IEquatable<SomeClass>
{
public override bool Equals(Object obj)
{
return Equals(obj as SomeClass);
}
public bool Equals(SomeClass obj)
{
if (obj == null)
return false;
return Id == obj.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
此结构还允许具有相同Id的派生程度较高的对象与派生程度较低的对象进行比较。如果这不是想要的行为,那么你也必须像在问题中那样比较类型。
if (obj.GetType() != typeof(SomeClass)) return false;
传统上,Equals
的实现方式是,只有两个对象在各个方面完全相同,它们才会"相等"。例如,如果数据库中有两个表示同一对象的对象,但其中一个具有与另一个不同的Name
属性,则这些对象不被视为"相等",并且应尽可能避免生成相同的"哈希代码"。
与其冒险调用两个不相等的对象,不如选择"不相等"。这就是为什么对象的默认实现使用对象本身的内存位置:除非两个对象完全是同一个对象,否则任何两个对象都不会被视为"相等"。所以我想说,除非你想同时写GetHashCode
和Equals
,让它们检查所有属性的相等性,否则最好不要重写这两个方法。
如果您有一个数据结构(如HashSet
),特别希望根据ID值确定相等性,则可以为该数据结构提供特定的IEqualityComparer
实现。
由于您不是在处理密封类,我建议不要像this.GetType() != obj.GetType()
那样检查类的相等性。SomeClass
的任何子类也应该能够参与Equals
,所以你可能想使用这个:
if (obj as SomeClass == null) return false;
您的第一个问题得到了极好的答案:
我做对了吗?
我会回答你的第二个问题
我的类是EntityFramework对象有关系吗?
是的,这很重要。实体框架内部大量使用HashSet
。例如,动态代理使用HashSet
来表示集合导航属性,而EntityObject
使用EntityCollection
,后者又在内部使用HashSet
。