Override Equals and GetHashCode in class with one field
Asked Answered
P

1

3

I have a class:

public abstract class AbstractDictionaryObject
    {
        public virtual int LangId { get; set; }

        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != GetType())
            {
                return false;
            }

            AbstractDictionaryObject other = (AbstractDictionaryObject)obj;
            if (other.LangId != LangId)
            {
                return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            int hashCode = 0;               
            hashCode = 19 * hashCode + LangId.GetHashCode();
            return hashCode;
        }

And I have derived classes:

public class Derived1:AbstractDictionaryObject
{...}

public class Derived2:AbstractDictionaryObject
{...}

In the AbstractDictionaryObject is only one common field: LangId.
I think this is not enough to overload methods (properly).
How can I identify objects?

Pryer answered 10/8, 2011 at 5:28 Comment(0)
L
7

For one thing you can simplify both your methods:

 public override bool Equals(object obj)
 {
     if (obj == null || obj.GetType() != GetType())
     {
         return false;
     }

     AbstractDictionaryObject other = (AbstractDictionaryObject)obj;
     return other.LangId == LangId;
 }

 public override int GetHashCode()
 {
     return LangId;
 }

But at that point it should be fine. If the two derived classes have other fields, they should override GetHashCode and Equals themselves, first calling base.Equals or base.GetHashCode and then applying their own logic.

Two instances of Derived1 with the same LangId will be equivalent as far as AbstractDictionaryObject is concerned, and so will two instances of Derived2 - but they will be different from each other as they have different types.

If you wanted to give them different hash codes you could change GetHashCode() to:

 public override int GetHashCode()
 {
     int hash = 17;
     hash = hash * 31 + GetType().GetHashCode();
     hash = hash * 31 + LangId;
     return hash;
 }

However, hash codes for different objects don't have to be different... it just helps in performance. You may want to do this if you know you will have instances of different types with the same LangId, but otherwise I wouldn't bother.

Loveridge answered 10/8, 2011 at 5:31 Comment(8)
"Two instances of Derived1 with the same LangId will be equivalent" - this is bad for my situation. Can I introduce the GUID field? Because i don't want to override in derived classes.Pryer
@user348173: If you want every instance to be unequal to every other instance, then why are you overriding Equals and GetHashCode at all? It's not clear what you're trying to achieve. When should two distinct objects be considered equal?Loveridge
they are equal if langId is equal and other field which exist in Derived1 is equal.Pryer
for example, I have two instances of Derived1: Class1 and Class2. The field LangId is equal, but other field (for example - Name) is different. So Class1 and Class2 should be not equal. But I don't want to override Equals and GetHashCode in Derived1.Pryer
@user348173: But you should override Equals and GetHashCode in Derived1. You could potentially use reflection to examine the fields, but that would be slow and very brittle - you might want to introduce a field which isn't part of the equality contract in Derived1. Fundamentally the base class can't predict which aspects of the class are part of its idea of equality - so you need to provide that behaviour within each derived class. Why don't you want to override GetHashCode/Equals within Derived1?Loveridge
@Pryer Then you would have to override Equals and GetHashCode in Derived1. A base does not know about fields you add to derived classes.Lyndell
@Jon Skeet: Initially, I did not have class AbstractDictionaryObject. And each class implements the Equals and GetHashCode. I wanted to do it only once, in the base class. Therefore, I have created class AbstractDictionaryObject.Pryer
@user348173: But it sounds like each class has its own fields and thus its own idea of equality - so you can't put that logic in one place. You could potentially write helper methods to pass the relevant information up to the base class, but fundamentally you've got to communicate the idea of "this set of information makes up the equality key" somehow from the derived class to the base class.Loveridge

© 2022 - 2024 — McMap. All rights reserved.