Since R# 2017.1.1 I get warnings in the automatically generated GetHashCode() function. Let me explain how this function is created:
If you override the Equals function of a class, R# suggests you to create equality members. If you let R# generate those equality members, it overrides the GetHashCode() function as well. In there however it uses all the properties of my class. As those properties aren't all read-only R# tells me that I should make them readonly and displays a warning.
So my question is wether I should just leave the GetHashCode() function empty (or delete those parts with warnings) or wether I should try to make the properties readonly so that R# isn't warning me anymore.
Here's my code:
public override bool Equals(object obj) => obj is RamEntry && Equals((RamEntry) obj);
public override int GetHashCode()
{
unchecked
{
var hashCode = (Value != null ? Value.GetHashCode() : 0); //In those 5 lines the warnings are being displayed
hashCode = (hashCode * 397) ^ Unimportant.GetHashCode(); //-------------------------------------------------
hashCode = (hashCode * 397) ^ (Comment?.GetHashCode() ?? 0);//-------------------------------------------------
hashCode = (hashCode * 397) ^ (Address?.GetHashCode() ?? 0);//-------------------------------------------------
hashCode = (hashCode * 397) ^ LastUpdated.GetHashCode(); //-------------------------------------------------
return hashCode;
}
}
private bool Equals(RamEntry other)
=> string.Equals(Value, other.Value) && Unimportant == other.Unimportant &&
string.Equals(Comment, other.Comment) && string.Equals(Address, other.Address);
This is the warning R# gives me if I delete the GetHashCode() function:

And this is the warning it gives me with the GetHashCode() function:

I think it's better explain on example why you should override GetHashCode when you override equality members, and also why you should not use mutable fields\properties when calculating hash code. Consider this simple class:
public class Test {
public string First { get; set; }
public string Second { get; set; }
}
Now you decide that two Test objects are equal if their First and Second properties are equal. You generate equality members but do not override GetHashCode:
public class Test {
public string First { get; set; }
public string Second { get; set; }
public override bool Equals(object obj) {
return obj is Test && Equals((Test)obj);
}
protected bool Equals(Test other) {
return string.Equals(First, other.First) && string.Equals(Second, other.Second);
}
public static bool operator ==(Test left, Test right) {
return Equals(left, right);
}
public static bool operator !=(Test left, Test right) {
return !Equals(left, right);
}
}
Then later you use your Test objects in something like Hashset.
var test1 = new Test();
test1.First = "a";
test1.Second = "b";
var set = new HashSet<Test>();
set.Add(test1);
var test2 = new Test();
test2.First = "a";
test2.Second = "b";
bool equal = test1 == test2; // true
bool contains = set.Contains(test2); // nope, false
Things went wrong - set clearly contains an item which is equals to test2, but
we failed to find it, because we did not override GetHashCode (here is a recent example of how things went badly wrong when this is violated: https://stackoverflow.com/a/43356217/5311735). So we implement it:
public override int GetHashCode() {
unchecked {
return ((First != null ? First.GetHashCode() : 0) * 397) ^ (Second != null ? Second.GetHashCode() : 0);
}
}
Now our problem is fixed and set.Contains return true. So far so good, but we are using mutable properties to calculate hash code. So consider this:
var test1 = new Test();
test1.First = "a";
test1.Second = "b";
var set = new HashSet<Test>();
set.Add(test1);
test1.First = "c";
var contains = set.Contains(test1); // nope, false
So we added item to hashset, modified one property and now set.Contains returns false for the exact same item we added couple of lines before. That is hash code has changed from the moment we placed item into a set and the moment we call Contains.
If you don't want such surprises - always override GetHashCode when you override equality members and do not use mutable fields\properties there.
You should either delete the whole GetHashCode() Stuff or implement it properly if you need its functionality.
If you only want to test for equality, you don't need it (Source):
Do not test for equality of hash codes to determine whether two objects are equal. (Unequal objects can have identical hash codes.) To test for equality, call the ReferenceEquals or Equals method
If you wonder when it should be implemented consider this link, which also contains basic implementation guidelines.
GetHashCode() give warningsGenerally GetHashCode() is used in - oh what a miracle - in Hashtables or Dictionarys. That's why you should ensure, that the hashcode at least doesn't change as long as the object is inside a collection and stuff which might rely on that value. That's why you get a Warning on not readonly members.
You can override GetHashCode for immutable reference types. In general, for mutable reference types, you should override GetHashCode only if:
– You can compute the hash code from fields that are not mutable; or – You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
GetHashCode() give a warning?I mean that's easy, imagine if you really had implemented a whole new strategy of when an Object is equal to another, you propably had a special hashcode-creation.
Actually the code part in your Equals Method really needs an implementation of GetHashCode(). Because equality is now no more depending on the Object-Instance on the Heap. So as @Evk points out, this is clearly a whole new Strategy of comparing objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With