Vincent Advocaat Vincent Advocaat - 14 days ago 6
C# Question

Producing the same hashcode if 2 array objects contain the same values

I am trying to calculate a hash code for one of my classes, the problem is: this class has a byte[] which returns a different hash for every object. I have made 2 objects of the class and both are instantiated with a new byte[0].

When overriding the Equals operator I've used Enumberable.SquenceEqual() to make sure the content of both array's are the same. But how would I make sure the arrays return the same hashcode if their contents are the same?

my code:

public override bool Equals(object obj)
{
return Equals(obj as MessageType);
}

{
if (messageType != null)
{
return (this.Identification == messageType.Identification) &&
(this.ActivateWindow == messageType.ActivateWindow) &&
(this.Logging == messageType.Logging) &&
(Enumerable.SequenceEqual(this.Pictogram, messageType.Pictogram) == true) &&
(this.Priority == messageType.Priority) &&
(this.Procedure == messageType.Procedure);
}

return false;
}

public override int GetHashCode()
{
var result = this.Identification != null ? this.Identification.GetHashCode() : 0;
result = (result * 397) ^ this.ActivateWindow.GetHashCode();
result = (result * 397) ^ this.Logging.GetHashCode();
result = (result * 397) ^ ((this.Pictogram != null) ? this.Pictogram.GetHashCode() : 0);
result = (result * 397) ^ this.Priority.GetHashCode();
result = (result * 397) ^ ((this.Procedure != null) ? this.Procedure.GetHashCode() : 0);
return result;
}

Answer

As far as I understand the question you should use Enumerable.SequenceEqual in Equals and some kind of aggregation within GetHashCode():

   byte[] extraData = ...

   ...

   public bool Equals(MessageType other) {
     ...

     if (!Enumerable.SequenceEqual(extraData, other.extraData))
       return false;

     ...  
   } 

   public override int GetHashCode() {
     unchecked { // we don't want IntegerOverflow exceptions to be thrown
       int result = ...

       ...  
       // let's combine hashes with xor
       result ^= extraData == null 
        ? 0
        : extraData.Aggerate(0, (s, a) => s ^ a); // ...and aggerate with xor as well

       ...

       return result;
     }
   }

In case extraData can be quite long (an appalling 1 GB for instance) you may want to restrict the computation to, say, 10 first items:

   result ^= extraData == null 
     ? 0
     : extraData.Take(10).Aggerate(0, (s, a) => s ^ a);
Comments