0

Is my current solution, (A, B, C, D, ...).GetHashCode(), guaranteed to always be the same for tuples with "Equal" items?

public class Pair
{
    public int X { get; set; }
    public int Y { get; set; }

    public Pair(int x, int y)
    {
        X = x;
        Y = y;
    }

    public override bool Equals(object other) => Equals(other as Pair);

    public virtual bool Equals(Pair other)
    {
        if (other is null)
        {
            return false;
        }
        if (object.ReferenceEquals(this, other))
        {
            return true;
        }
        if (this.GetType() != other.GetType())
        {
            return false;
        }
        return X == other.X && Y == other.Y;
    }

    public override int GetHashCode() => (X, Y).GetHashCode();

    public static bool operator ==(Pair lhs, Pair rhs)
    {
        if (lhs is null)
        {
            if (rhs is null)
            {
                return true;
            }
            return false;
        }
        return lhs.Equals(rhs);
    }

    public static bool operator !=(Pair lhs, Pair rhs) => !(lhs == rhs);
}

In this code always guaranteed to print 1:

var uniquePairs = new HashSet<Pair>();
uniquePairs.Add(new Pair(2, 4));
uniquePairs.Add(new Pair(2, 4));
uniquePairs.Add(new Pair(2, 4));
uniquePairs.Add(new Pair(2, 4));
Console.WriteLine(uniquePairs.Count);

What about for a greater number of non-trivial type properties?

What are reliable GetHashCode solutions that can be used for classes like these, which guarantee equal hashodes if all (not-necessarily-int) members are the same?

theonlygusti
  • 11,032
  • 11
  • 64
  • 119
  • [not](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=net-6.0) **A hash code is not a permanent value** – Lei Yang Jan 13 '22 at 03:02
  • 1
    @LeiYang whether or not the hash code is preserved from runtime to runtime is irrelevant – theonlygusti Jan 13 '22 at 03:04
  • i think in your use case hashcode can be reliable(all things only happen only in one process). acutally this is they way many compound objects get hashcode. – Lei Yang Jan 13 '22 at 03:05
  • @LeiYang I've seen this pattern before, very often, but [this answer](https://stackoverflow.com/a/55541902/3310334) "combining the hash codes of each object (and an **additional random seed**)" made me want to check – theonlygusti Jan 13 '22 at 03:08
  • if you mean the microsoft implementaion, i think they avoid `GetHashCode` for better performance. – Lei Yang Jan 13 '22 at 03:16
  • Why are you writing a Tuple class when tuple support is already in the platform? – Ian Mercer Jan 13 '22 at 03:16
  • @IanMercer i'm just demonstrating the question I have about Tuple.GetHashCode with some "real" code. – theonlygusti Jan 13 '22 at 03:18
  • You could have stopped after the first line. Yes, tuples compare equal when the values are equal and must have the same hashcode otherwise `Dictionary<(tuple),U>` wouldn't work. e.g. https://intellitect.com/overidingobjectusingtuple/ – Ian Mercer Jan 13 '22 at 04:24

1 Answers1

0

People usually use some arithmetic with factors derived from the values of fields to provide a good pseudo-random distribution but will compute to the same thing if all fields are equal. Have a look at this:

General advice and guidelines on how to properly override object.GetHashCode()

Also, look at the Microsoft documentation if you want more information on the subject.

If your goal is simply to have classes whose equality is determined by fields matching rather than by reference, C# has a new record reference type you can use which does this by default. If you're using the latest version of C#/.NET this would be the way to go.

If you get into anything really complicated that has to be secure, consider looking into using some robust hash algorithms like SHA-256 ... take all your fields and turn them into a padded buffer or bytes and run them through SHA-256 (all this is found in System.Security.Cryptography). You'll take the SHA-256 output and select 4 bytes of it to produce a 32-bit integer. Collision is very, very unlikely (but of course it's still possible with only 32-bits).