Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
326 views
in Technique[技术] by (71.8m points)

c# - Should an override of Equals on a reference type always mean value equality?

Without doing anything special for a reference type, Equals() would mean reference equality (i.e. same object). If I choose to override Equals() for a reference type, should it always mean that the values of the two objects are equivalent?

Consider this mutable Person class:

class Person
{
    readonly int Id;

    string FirstName { get; set; }
    string LastName { get; set; }
    string Address { get; set; }
    // ...
}

Two objects that represent the exact same person will always have the same Id, but the other fields might be different over time (i.e. before/after an address change).

For this object Equals could be defined to mean different things:

  • Value Equality: all fields are equal (two objects representing the same person but with different addresses would return false)
  • Identity Equality: the Ids are equal (two objects representing the same person but with different addresses would return true)
  • Reference Equality: i.e. don't implement Equals.

Question: Which (if any) of these is preferable for this class? (Or perhaps the question should be, "how would most clients of this class expect Equals() to behave?")

Notes:

  • Using Value Equality makes it more difficult to use this class in a Hashset or Dictionary
  • Using Identity Equality makes the relationship between Equals and the = operator strange (i.e. after a check of two Person objects (p1 and p2) returns true for Equals(), you might still want to update your reference to point to the "newer" Person object since it is not value equivalent). For example, the following code reads strange--seems like it does nothing, but it is actually removing p1 and adding p2:

    HashSet<Person> people = new HashSet<Person>();
    people.Add(p1);
    // ... p2 is an new object that has the same Id as p1 but different Address
    people.Remove(p2);
    people.Add(p2);
    

Related Questions:

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Yes, deciding the right rules for this is tricky. There is no single "right" answer here, and it will depend a lot on both context and preference Personally, I rarely bother thinking about it much, just defaulting to reference equality on most regular POCO classes:

  • the number of cases when you use something like Person as a dictionary-key / in a hash-set is minimal
    • and when you do, you can provide a custom comparer that follows the actual rules you want it to follow
    • but most of the time, I'd use simply the int Id as the key in a dictionary (etc) anyway
  • using reference equality means that x==y gives the same result whether x/y are Person or object, or indeed T in a generic method
  • as long as Equals and GetHashCode are compatible, most things will just about work out, and one easy way to do that is to not override them

Note, however, that I would always advise the opposite for value-types, i.e. explicitly override Equals / GetHashCode; but then, writing a struct is really uncommon


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...