-1

I have classes:

public class A : IEquatable<A>
{
  ...
  public bool Equals(A data) { ... }
}

public class B
{
   ...
}

and a generic class for custom job

public class CommonFilter<T>
{
   public T GetBy(T data) {
      var item = list.FirstOrDefault(s=> s?.Equals(data) == true);
      ...
   }
}

list if List<T> type.

CommonFilter<A> cmA = GetFilter();
var result = cmA.GetBy(data);

In debug mode, if I have object like CommonFilter<A>, I expected that in LINQ to use Equals method from A class, but it doesn't.

How to achieve this ?

Snake Eyes
  • 16,287
  • 34
  • 113
  • 221
  • 2
    You also need to override `Equals(object)` in `A`. – Sweeper Mar 24 '20 at 17:03
  • I know because I put breakpoint in VS 2019, it is not reached – Snake Eyes Mar 24 '20 at 17:03
  • IIRC, `EqualityComparer.Equals(s, data)` should select the right `Equals`. – Sweeper Mar 24 '20 at 17:05
  • Without a good [mcve] it's impossible to know for sure why your code doesn't work. However, most likely you haven't fully implemented equality in your type. See marked duplicate, as well as the hundreds of other equality-related questions on Stack Overflow, for details about how to do it correctly. If you still are having trouble after reviewing all of that material, post a new question but this time make sure you provide a proper [mcve] that reliably reproduces the problem with an explanation of what _specifically_ you can't figure out. – Peter Duniho Mar 24 '20 at 17:12
  • Further, it is possible that your call site simply doesn't have access to the full type information and thus is calling the wrong `Equals()` method. This would not be an issue if you'd implemented equality correctly (since the `object.Equals()` method would work just as well as the interface method, albeit with boxing overhead), but you can get away with it if you declare your constraint correctly. See other marked duplicate for that particular issue. – Peter Duniho Mar 24 '20 at 17:19
  • @PeterDuniho, Gvien that two people have successfully answered the question, I think it's fair to say the question was clear enough. – Jasper Kent Mar 24 '20 at 17:21
  • @Jasper: a) people guessing the right answer doesn't make the question clear enough, b) no one should've been answering a question that's already been answered plenty of times before, and c) no one should tolerate a debugging question that doesn't include a [mcve]. – Peter Duniho Mar 24 '20 at 17:23
  • a) I didn't guess; the answer was clear. b) True, but I never mentioned it c) I didn't need to debug, the answer was clear. – Jasper Kent Mar 24 '20 at 17:34

2 Answers2

3

As Jasper points out, you are missing a generic constraint:

public class CommonFilter<T> where T : IEquatable<T>

Whats not explained in the other answer is why its needed.

Bear in mind that the compiler needs to resolve the call s?.Equals(data) at compile time. In your code the compiler knows nothing about T and therefore resolves the call to the only possible candidate for any T: object.Equals which defaults to reference comparison.

If, on the other hand, you define the constraint then the compiler knows that any given T must implement the more specific IEquatable<T>.Equals and will resolve the call to that method.

If defining the constraint is a breaking change or you simply can't implement it because you also need to process data where reference equality is appropiate then you could branch inside GetBy on whether T implements IEquatable<T> or not, Type checking a generic type is normally a red flag but it could be justifiable in this particular scenario.

If possible, I prefer the first option because that way you specifically forbid using GetBy with types that do not implement IEquatable<T>.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • Always love answers like this. Explaining the *why* is just as important as the *what*, if not more important. – RoadRunner Mar 24 '20 at 17:39
2

I think you need:

public class CommonFilter<T> where T : IEquatable<T>
Jasper Kent
  • 3,546
  • 15
  • 21