Overriding equals () but not checking all fields - what will happen?

If I override Equals and GetHashCode, how do I decide which fields to compare? And what happens if I have two objects with two fields each, but Equals only checks one field?

In other words, let's say I have this class:

class EqualsTestClass { public string MyDescription { get; set; } public int MyId { get; set; } public override bool Equals(object obj) { EqualsTestClass eq = obj as EqualsTestClass; if(eq == null) { return false; } else { return MyId.Equals(eq.MyId); } } public override int GetHashCode() { int hashcode = 23; return (hashcode * 17) + MyId.GetHashCode(); } } 

I consider two Equal objects if they have the same MyId. Therefore, if Id is equal, but the description is different, they are still considered equal.

I just wonder what are the pitfalls of this approach? Of course, this design will behave as expected:

  List<EqualsTestClass> test = new List<EqualsTestClass>(); EqualsTestClass eq1 = new EqualsTestClass(); eq1.MyId = 1; eq1.MyDescription = "Des1"; EqualsTestClass eq2 = new EqualsTestClass(); eq2.MyId = 1; eq2.MyDescription = "Des2"; test.Add(eq1); if (!test.Contains(eq2)) { // Will not be executed, as test.Contains is true test.Add(eq2); } 

As eq2, the value is eq1, it will not be added. But this is the code that I control, but I wonder if there is code in the structure that can cause unforeseen problems?

So, should I always add all the public fields to my Equals () comparison, or what recommendations should I avoid unpleasant surprise due to a bad Framework-Mojo that was completely unexpected?

+6
c #
source share
6 answers

The reason for overriding Equals() is because you define what it means for two instances equal. In some cases, this means that all fields must be equal, but this is not necessary. You decide.

See the documentation and post for more information.

+11
source share

I do not think you need to worry about the Framework in this case. If you, as a class constructor, consider two instances of this class equal, if they have the same MyId, then you only need to check MyId in your overridden Equals () and GetHashCode () methods.

+1
source share

You only need to check the fields that are necessary for matching, if all you need to match is an identifier, then go to it.

+1
source share

Question: If I override Equals and GetHashCode, how can I decide which fields I compare?

It depends on what you are trying to accomplish. If you are trying to find out if the objects are the same, you should compare them all. If you have a โ€œkeyโ€ and you only want to know if they are the same โ€œobjectโ€, even if the other data is different, just check the values โ€‹โ€‹of the โ€œkeyโ€.

And what happens if I have two objects with two fields each, but Equals only checks one field?

Then you will have an equality method that simply checks if the "key" is the same, and potentially can have several "equal" objects with internal deviations.

+1
source share

Others said that this is perfectly fair and expected, and exactly how Equals should work. Therefore, there is no problem with him as a class.

I would be very a little wary of this as an API. Forgive me if this is not what was intended: in this case, this is just a note of caution for others.

The potential problem is that API users naturally expect equal objects to be "the same." This is not part of the equality treaty, but it is part of the common sense of the word. The class looks a bit like a binary tuple, but it is not one, so this should be reasonable.

An example of such a reasonable reason is that one field is a "visible implementation detail", for example, the maximum load factor in a container based on a hash table. An example of a dangerous (albeit tempting) reason is "because I added a description in the future and did not want to change the Equals method if it broke something."

Thus, it is fully valid to make something a little contrary to intuition, especially if you clearly confirm that the behavior may be unexpected. Such Equals methods must be supported, because their prohibition will be crazy in cases where the field, obviously, does not matter. But it should be clear why it makes sense to create two pairs of ID descriptions with the same identifier and different descriptions, but it does not make sense to add them as a container (for example, HashSet) that uses Equals / HashCode to prevent duplicate entries.

+1
source share

Your example checks to see if the list (EqualsTestClass) contains an object of the same type with the same property values. Another way to accomplish this task without redefining peers (and the traditional understanding of peers) is to use a custom resolver. It will look something like this (in VB):

 Public Class EqualsTestComparer Implements IEqualityComparer(Of EqualsTestClass) Public Function Equals1(ByVal x As EqualsTestClass, ByVal y As EqualsTestClass) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).Equals If x.MyId = y.MyId and x.MyDescription = y.MyDescription Then Return True Else Return False End If End Function Public Function GetHashCode1(ByVal obj As EqualsTestClass) As Integer Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).GetHashCode Return obj.ToString.ToLower.GetHashCode End Function End Class 

Then, in your program, you simply use a custom resolver:

 If Not test.Contains(eq2, New EqualsTestComparer) Then //Do Stuff End if 
0
source share

All Articles