2

I read in a few places that LINQ equals (in join syntax) calls IEquatable for the type it's comparing, but I don't see it happening in my join:

List<ILData> list1 = new List<ILData> { /* Initialized with items */ };
List<ILData> list2 = new List<ILData> { /* Initialized with items */ };

var joinItems = (
    from d1 in list1
        join d2 in list2
        on d1 equals d2
    where d1.SomeValue == "7"
    select d1).Distinct().ToList<ILData>();

Assuming I provided an interface definition satisfying:

ILData : IEquatable<ILData>

requirements, why wouldn't I be seeing ILData::Equals get called in this case?

John Humphreys
  • 37,047
  • 37
  • 155
  • 255

2 Answers2

5

It uses EqualityComparer<T>.Default. Since your type implements IEquatable<T>, the actual comparer used will be an internal class called System.Collections.Generic.GenericEqualityComparer<T>, which will delegate GetHashCode and Equals requests to your object.GetHashCodemethod and IEquatable<ILData>.Equals methods respectively (except for null references, where it returns a zero hash-code / does a reference-equality check without calling your methods).

There are a number of reasons that could explain your Equals method not being hit:

  1. There's an empty sequence at play here.
  2. Your breakpoint is on object.Equals rather than IEquatable<ILData>.Equals
  3. The second sequence only contains null references (this is checked by the framework comparer, so it won't enter yours).
  4. There are no hash matches (from GetHashCode), so the join operation never needs to do a full equality check. One reason this might be happening is that you forgot to override this method and are therefore stuck with the default one from object (which is designed for reference equality and will be inconsistent with your definition of equality).
Ani
  • 111,048
  • 26
  • 262
  • 307
  • My comparison logic is complicated enough that I can't represent any of it with a GetHashCode result, so I made GetHashCode return a constant so Equals() gets called every time. So, #4 was the ticket :) – John Humphreys Jul 10 '12 at 17:20
0

The Join function says it uses the default equality comparer. You need to override object.GetHashCode (and should override object.Equals) in addition to implementing IEquatable.

In general, the query

from AA in AAAA
join BB in BBBB
on C(AA) equals D(BB)
select E(AA,BB)

translates to

AAAA.Join(BBBB, AA => C(AA), BB => D(BB), (AA, BB) => E(AA, BB))
Random832
  • 37,415
  • 3
  • 44
  • 63