可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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/
回答2:
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;
回答3:
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;
回答4:
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.
回答5:
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.