2

I created class with overriden Equals. The problem is that Distinct method doesn't work for my class.

class MyClass
{
    public int Item1 { get; private set; }
    public int Item2 { get; private set; }

    public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2); 


    public override bool Equals(object obj)
    {
        var other = obj as MyClass;

        if (other == null)
        {
            return false;
        }

        return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClass x = new MyClass(1, 0);
        MyClass y = new MyClass(1, 0);
        var list = new List<MyClass>();
        list.Add(x);
        list.Add(y);


        bool b = x.Equals(y));  //True
        var distincts = list.Distinct(); //Doesn't work, contains both
    }
}

How can I fix that and why it doesn't use my Equals in Distinct?

Dork
  • 1,816
  • 9
  • 29
  • 57
  • 1
    `MyClass` should also override `GetHashCode` since it overrides `Equals`. There's even a compiler warning for it. – Dirk Jun 07 '17 at 08:31
  • You should also override the `GetHashCode` method like this: https://stackoverflow.com/a/38434457/2946329 – Salah Akbari Jun 07 '17 at 08:31
  • All set methods need `GetHashCode`(before `Equals` is used). But in general you should always implement `GetHashCode` **and** `Equals` together – Tim Schmelter Jun 07 '17 at 08:32

3 Answers3

3

Distinct docs:

Returns distinct elements from a sequence by using the default equality comparer to compare values.

Let's see what the default equality comparer does:

The Default property checks whether type T implements the System.IEquatable<T> interface and, if so, returns an EqualityComparer<T> that uses that implementation. Otherwise, it returns an EqualityComparer<T> that uses the overrides of Object.Equals and Object.GetHashCode provided by T.

So basically, to make this work, you either:

  • implement GetHashCode as well
  • implement IEquatable<T>
  • Call the overload of Distinct that accepts a custom equality comparer.

If I were you, I would choose the second one because you need to change the least of your code.

class MyClass: IEquatable<MyClass> {
    ...

    public bool Equals(MyClass obj)
    {
        if (obj == null)
        {
            return false;
        }

        return (this.Item1 == obj.Item1 && this.Item2 == obj.Item2);
    }
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
2

You have to override GetHashCode as well:

public override int GetHashCode()
{
    return Item1; // or something
}

Distinct first compares the hashcodes, which should be computed faster than the actual Equals. Equals is only further evaulated if the hashcodes are equal for two instances.

adjan
  • 13,371
  • 2
  • 31
  • 48
1

You need to implement IEquatable<MyClass> in MyClass and provide your own implementation of GetHashCode and Equals method.

see this for more information.

class MyClass
{
    public int Item1 { get; private set; }
    public int Item2 { get; private set; }

    public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2); 


    public override bool Equals(object obj)
    {
        var other = obj as MyClass;

        if (other == null)
        {
            return false;
        }

        return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
    }

    public override int GetHashCode()
    {

        return this.Item1;
    }
}
Jenish Rabadiya
  • 6,708
  • 6
  • 33
  • 62