What's the best strategy for Equals and GetHashCode?

后端 未结 7 1978
你的背包
你的背包 2020-11-28 11:25

I\'m working with a domain model and was thinking about the various ways that we have to implement these two methods in .NET. What is your preferred strategy?

This i

7条回答
  •  野性不改
    2020-11-28 12:17

    None of the answers here really hit the spot for me. Since you already said that you can't use Id for equality, and you need to use a bundle of properties, here's a better way to do that. Note: I do not consider this overall to be the best way to implement Equals and GetHashCode. This is a better version of the OP's code.

    public override bool Equals(object obj) {
       var myClass = obj as MyClass;
    
       if (myClass != null) {
          // Order these by the most different first.
          // That is, whatever value is most selective, and the fewest
          // instances have the same value, put that first.
          return this.Id == myClass.Id
             && this.Name == myClass.Name
             && this.Quantity == myClass.Quantity
             && this.Color == myClass.Color;
       } else {
          // This may not make sense unless GetHashCode refers to `base` as well!
          return base.Equals(obj);
       }
    }
    
    public override int GetHashCode() {
       int hash = 19;
       unchecked { // allow "wrap around" in the int
          hash = hash * 31 + this.Id; // assuming integer
          hash = hash * 31 + this.Name.GetHashCode();
          hash = hash * 31 + this.Quantity; // again assuming integer
          hash = hash * 31 + this.Color.GetHashCode();
       }
       return hash;
    }
    

    See this answer by Jon Skeet for some of the reasoning behind this. Using xor is not good because various sets of data can end up resulting in the same hash. This wrap-around method with primes (the seed values of 19 and 31 above, or other values that you choose) does a better job of segmenting into "buckets" that have few collisions each.

    If any of your values can be null, I encourage you to think carefully about how they should compare. You could use short circuit null evaluation and the null coalescing operator perhaps. But make sure that if nulls should compare as equal that you assign different hash codes to the different nullable properties when they are null.

    Also, I'm not convinced that your Equals implementation makes any sense. When two objects are compared for equality, first their GetHashCode values are compared. Only if those are different is the Equals method run (so that if two objects that hash to the same value are different, this will be detected). Since your GetHashCode implementation doesn't refer to the base, it may make no sense for your Equals method to do so. Specifically, you will have a serious bug waiting to break things if Equals can return true for two objects whose hash codes are different.

提交回复
热议问题