Differences between IEquatable, IEqualityComparer, and overriding .Equals() when using LINQ on a custom object collection?

后端 未结 3 956
隐瞒了意图╮
隐瞒了意图╮ 2020-12-04 22:25

I\'m having some difficulty using Linq\'s .Except() method when comparing two collections of a custom object.

I\'ve derived my class from Object and imp

相关标签:
3条回答
  • 2020-12-04 22:42

    You cannot "allow some tolerance on LastUpdate" and then use a GetHashCode() implementation that uses the strict value of LastUpdate!

    Suppose the this instance has LastUpdate at 23:13:13.933, and the obj instance has 23:13:13.932. Then these two might compare equal with your tolerance idea. But if so, their hash codes must be the same number. But that will not happen unless you're extremely extremely lucky, for the DateTime.GetHashCode() should not give the same hash for these two times.

    Besides, your Equals method most be a transitive relation mathematically. And "approximately equal to" cannot be made transitive. Its transitive closure is the trivial relation that identifies everything.

    0 讨论(0)
  • 2020-12-04 22:49

    The basic pattern I use for equality in an object is the following. Note that only 2 methods have actual logic specific to the object. The rest is just boiler plate code that feeds into these 2 methods

    class MyObject : IEquatable<MyObject> { 
      public bool Equals(MyObject other) { 
        if (Object.ReferenceEquals(other, null)) {
          return false;
        }
    
        // Actual equality logic here
      }
    
      public override int GetHashCode() { 
        // Actual Hashcode logic here
      }
    
      public override bool Equals(Object obj) {
        return Equals(obj as MyObject);
      }
    
      public static bool operator==(MyObject left, MyObject right) { 
        if (Object.ReferenceEquals(left, null)) {
          return Object.ReferenceEquals(right, null);
        }
        return left.Equals(right);
      }
    
      public static bool operator!=(MyObject left, MyObject right) {
        return !(left == right);
      }
    }
    

    If you follow this pattern there is really no need to provide a custom IEqualityComparer<MyObject>. The EqualityComparer<MyObject>.Default will be enough as it will rely on IEquatable<MyObject> in order to perform equality checks

    0 讨论(0)
  • 2020-12-04 22:50

    It doesn't matter whether you override object.Equals and object.GetHashCode, implement IEquatable, or provide an IEqualityComparer. All of them can work, just in slightly different ways.

    1) Overriding Equals and GetHashCode from object:

    This is the base case, in a sense. It will generally work, assuming you're in a position to edit the type to ensure that the implementation of the two methods are as desired. There's nothing wrong with doing just this in many cases.

    2) Implementing IEquatable

    The key point here is that you can (and should) implement IEquatable<YourTypeHere>. The key difference between this and #1 is that you have strong typing for the Equals method, rather than just having it use object. This is both better for convenience to the programmer (added type safety) and also means that any value types won't be boxed, so this can improve performance for custom structs. If you do this you should pretty much always do it in addition to #1, not instead of. Having the Equals method here differ in functionality from object.Equals would be...bad. Don't do that.

    3) Implementing IEqualityComparer

    This is entirely different from the first two. The idea here is that the object isn't getting it's own hash code, or seeing if it's equal to something else. The point of this approach is that an object doesn't know how to properly get it's hash or see if it's equal to something else. Perhaps it's because you don't control the code of the type (i.e. a 3rd party library) and they didn't bother to override the behavior, or perhaps they did override it but you just want your own unique definition of "equality" in this particular context.

    In this case you create an entirely separate "comparer" object that takes in two different objects and informs you of whether they are equal or not, or what the hash code of one object is. When using this solution it doesn't matter what the Equals or GetHashCode methods do in the type itself, you won't use it.


    Note that all of this is entirely unrelated from the == operator, which is its own beast.

    0 讨论(0)
提交回复
热议问题