警告:“...覆盖Object.Equals(对象o)但不覆盖Object.GetHashCode()”

时间:2011-06-24 15:27:13

标签: c# .net entity-framework

我覆盖了我班级的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类型。 我的类是实体框架对象是否重要?

5 个答案:

答案 0 :(得分:31)

正如其他人所说,反对平等的使用似乎很狡猾。抛开这一点,让我们专注于GetHashCode。

如果两个对象相同,那么您必须不违反GetHashCode的主要规则是,那么它们必须具有相同的哈希码。或者,如果两个对象具有不同的哈希码,则表示的等效方式则必须是不相等的。您的实现在那里看起来很好。

你可以自由地违反反过来。也就是说,如果两个对象具有相同的哈希码,则允许它们相等或不相等,如您所见。

我假设“Id”是一个不可变的属性。如果“Id”可以在对象的生命周期内更改,那么将对象放入哈希表时可能会出现问题。考虑确保在计算相等性和哈希码时只使用不可变属性。

您的实现看起来不错,但您提出问题的事实表明您可能无法掌握构建GetHashCode实现的所有细微因素。一个好的起点是我关于这个主题的文章:

http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/

答案 1 :(得分:8)

对我而言看起来是正确的。每当我做这样的事情时,我通常也会实现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;

答案 2 :(得分:6)

由于您没有处理密封类,我建议不要像this.GetType() != obj.GetType()那样检查类的相等性。 SomeClass的任何子类也应该能够参与Equals,因此您可能希望使用此类:

if (obj as SomeClass == null) return false;

答案 3 :(得分:5)

传统上Equals的实现方式是,如果两个对象在各个方面完全相同,那么它们只是“等于”。例如,如果有两个对象代表数据库中的同一个对象,但是其中一个对象具有不同的Name属性,则对象不会被视为“等于”,并且应该避免生成相同的对象。哈希码“如果可能的话。

最好在“不平等”方面犯错,而不是冒险调用两个不相等的对象。这就是对象的默认实现使用对象本身的内存位置的原因:除非它们是完全相同的对象,否则不会将两个对象视为“相等”。所以我要说除非你想以这样的方式写GetHashCodeEquals来检查它们所有属性的相等性,否则你最好不要覆盖任何一种方法。

如果您有一个数据结构(如HashSet),您特别希望根据ID值确定相等性,则可以为该数据结构提供特定的IEqualityComparer实现。

答案 4 :(得分:5)

你的第一个问题得到了很好的答案:

  

我做得对吗?

我会回答你的第二个问题

  

我的类是实体框架对象是否重要?

是的,这很重要。实体框架在内部使用HashSet。例如,动态代理使用HashSet表示集合导航属性,使用EntityObject使用EntityCollection,然后在内部使用HashSet