简体   繁体   中英

Warning: “… overrides Object.Equals(object o) but does not override Object.GetHashCode()”

I overrode the Equals() of my class to compare ID values of type Guid.

Then Visual Studio warned:

... overrides Object.Equals(object o) but does not override Object.GetHashCode()

So I then also overrode its GetHashCode() like this:

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();
    }
}

It seems to work. Have I done this correctly? Remember Id is of type Guid. Does it matter that my class is an Entity Framework object?

As others have said, the use of Reflection in Equals seems dodgy. Leaving that aside, let's concentrate on GetHashCode.

The primary rule for GetHashCode that you must not violate is if two objects are equal then they must both have the same hash code . Or, an equivalent way of saying that is if two objects have different hash codes then they must be unequal. Your implementation looks good there.

You are free to violate the converse. That is, if two objects have the same hash code then they are permitted to be equal or unequal, as you see fit.

I am assuming that "Id" is an immutable property. If "Id" can change over the lifetime of the object then you can have problems when putting the object in a hash table. Consider ensuring that only immutable properties are used in computing equality and hash code.

Your implementation looks good but the fact that you are asking the question indicates that you might not have a solid grasp of all the subtle factors that go into building an implementation of GetHashCode. A good place to start is my article on the subject:

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

It looks correct to me. Whenever I do something like this, I usually also implement IEquatable so that comparisons between variables of the same compile-time type will be a little more effecient.

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();
     }
} 

This structure also allows a more derived object with the same Id to compare as equal to a less derived object. If this is not the desired behavior, then you will have to also compare the types as you do in the question.

if (obj.GetType() != typeof(SomeClass)) return false;

Since you're not dealing with a sealed class, I'd recommend against checking for class equality like this this.GetType() != obj.GetType() . Any sub-class of SomeClass should be able to participate in Equals also, so you might want to use this instead:

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

Traditionally Equals is implemented in such a way that two objects will only be "Equal" if they are exactly the same in every way. For example, if you have two objects that represent the same object in the database, but where one has a different Name property than the other, the objects aren't considered "Equal", and should avoid producing the same "Hashcode" if possible.

It is better to err on the side of "not equal" than to risk calling two objects equal that aren't. This is why the default implementation for objects uses the memory location of the object itself: no two objects will ever be considered "equal" unless they are exactly the same object. So I'd say unless you want to write both GetHashCode and Equals in such a way that they check for equality of all their properties, you're better off not overriding either method.

If you have a data structure (like a HashSet ) where you specifically want to determine equality based on the ID value, you can provide a specific IEqualityComparer implementation to that data structure.

You got excelent answers to your first question:

Have I done it correctly?

I will answer your second question

Does it matter that my class is an Entity Framework object?

Yes it matters a lot. Entity framework uses HashSet a lot internally. For example dynamic proxies use HashSet for representing collection navigation properties and EntityObject s use EntityCollection which in turn uses HashSet internally.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM