0

I have a simple class, which holds a list of points:

public class PointCollection {

    public List<PointModel> list;

    public PointCollection()
    {
        list = new List<PointModel>();
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + list.GetHashCode();
        return hash;
    }
}

Here's how looks PointModel class:

public class PointModel
{
    public float x = 0f;
    public float y = 0f;

    public PointModel()
    {
        x = y = 0;
    }

    public PointModel(float _x, float _y)
    {
        x = _x;
        y = _y;
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + x.GetHashCode();
        hash = (hash * 7) + y.GetHashCode();
        return hash;
    }
}

However, GetHashCode from PointCollection doesn't work properly. It always returns a different value and GetHashCode from PointModel is never called.

To have this working I have to explicitly iterate through a list and call GetHashCode for each point:

public override int GetHashCode()
{
    int hash = 13;
    for (int i = 0; i < list.Count; i++)
    {
        hash = (hash * 7) + list[i].GetHashCode();
    }
    return hash;
}

Why is that? I have different classes with similar configurations and it works fine, but not in this case.

Makalele
  • 7,431
  • 5
  • 54
  • 81
  • [`List`](https://github.com/microsoft/referencesource/blob/master/mscorlib/system/collections/generic/list.cs) doesn't implement `GetHashCode`, so it uses the base implementation: [`Object.GetHashCode()`](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1). You can see a discussion about this implementation [here](https://stackoverflow.com/questions/720177/default-implementation-for-object-gethashcode). – ProgrammingLlama Jul 03 '20 at 08:05
  • Yes, I couldn't find such a question though. – Makalele Jul 03 '20 at 08:36

1 Answers1

2

List<> doesn't override GetHashCode, so it will call the base implementation of Object.

As you've discovered, if you want to hash the contents on a list you need to iterate over it and do it manually.

If you're a fan of Linq you can calculate the hash using the Aggregate method:

var hash = list.Aggregate(13, (agg, curr) => (agg * 7) + curr.GetHashCode());
Sean
  • 60,939
  • 11
  • 97
  • 136
  • 1
    I have a lot of different cases like this (List) and I thought GetHashCode were called, but it seems like it's not true. So I have to change a lot of GetHashCode implementations. Thanks for the answer and also for the Linq snippet :) – Makalele Jul 03 '20 at 08:35