-1

When I use this comparer in Distinct() it always returns false. Can't see a reason why.

public class IdEqualityComparer : IEqualityComparer<Relationship>
{
    public bool Equals(Relationship x, Relationship y)
    {
        if (x == null && y == null)
            return true;
        else if (x == null || y == null)
            return false;
        else if (x.ID == y.ID && x.RelatedID == y.RelatedID)
            return true;
        else
            return false;
    }

    public int GetHashCode(Relationship obj)
    {
        unchecked
        {
            int hash = (obj.ID ?? "").GetHashCode() ^ (obj.RelatedID ?? "").GetHashCode();
            return hash;
        }
    }
}

The hash seems correct to me, but the ID and RelatedID comparison never returns true.

It fails, as I can check the result afterward and the output is not distinct using those two properties.

Paul Keefe
  • 44
  • 3
  • 1
    `The hash seems correct to me, but the ID and RelatedID comparison never returns true.` <= please provide an [mcve] with a comparison between 2 instances that should return `true` but currently returns `false`. **Also remember to override `bool Equals(object other)` as well when you can't provide the IEqualityComparer!!** – Igor Apr 06 '18 at 15:19
  • 1
    are you perhaps comparing objects where one is `""` and the other is `null`? this will cause the `GetHashCode()` to give the same value, but Equals` to return `false`. Note that this is **not** an invalid scenario - that's perfectly allowed. What *isn't* allowed is `Equals` returning true and `GetHashCode` returning *different* values. But ultimately, it would *really* help to see a full example here. – Marc Gravell Apr 06 '18 at 15:24

2 Answers2

1

Apologies to all! It is working fine.

I was comparing objects defined similarly to Marc's answer. But, I did this:

var relators = relationships.Distinct(new RelationshipEqualityComparer());

and then sent relationships, rather than realtors, to the next method where the items were reviewed. Sometimes it takes another pair of eyes!

Thanks!

Paul Keefe
  • 44
  • 3
0

Seems to work fine here;

static void Main()
{
    var objs = new[]
    {
        new Relationship { ID = "a", RelatedID = "b" }, // <----\
        new Relationship { ID = "a", RelatedID = "c" }, //      |
        new Relationship { ID = "a", RelatedID = "b" }, // dup--/
        new Relationship { ID = "d", RelatedID = "b" }, // <------\
        new Relationship { ID = "d", RelatedID = "c" }, //        |
        new Relationship { ID = "d", RelatedID = "b" }, // dup ---/ 
        new Relationship { ID = "b", RelatedID = "c" }, //
    };

    var count = objs.Distinct(new IdEqualityComparer()).Count();
    System.Console.WriteLine(count);
}

gives 5, not 7 (which we would expect if it always returned false). Tested with:

public class Relationship
{
    public string ID { get; set; }
    public string RelatedID { get; set; }
}

To illustrate this more clearly:

var a = new Relationship { Id = "x", RelatedID = "foo" };
var b = new Relationship { Id = "y", RelatedID = "foo" };
var c = new Relationship { Id = "x", RelatedID = "foo" };

we can now demonstrate that the comparer returns true and false appropriately:

var comparer = new IdEqualityComparer();
Console.WriteLine(comparer.Equals(a, b)); // False
Console.WriteLine(comparer.Equals(a, c)); // True

we can also show that the hash-code is working appropriately:

Console.WriteLine(comparer.GetHashCode(a));
Console.WriteLine(comparer.GetHashCode(b));
Console.WriteLine(comparer.GetHashCode(c));

note that the numbers will change, but for me on this run this gives:

-789327704
1132350395
-789327704

The numbers don't matter - what matters is that the first and last are equal, and (ideally) different from the middle one.

So: the comparer is working fine, and the premise of the question is incorrect. You need to identify in your code what is different, and fix it.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900