In part it is because you want to design your classes in such a way that it's easy to use.
For example It's much easier to write/Lattitude
coordinate1.Equals(coordinate2)
Than if you write it like this
cooridate1.Latitude == coordinate2.Latitude && cooridnate2.Longitude == cooridnate2.Longitude
Also in a bit more complex cases it's just too easy to make mistakes. For example if you write
price.Amount == price2.Amount
now you forgot to include the currency. And for some value objects you might evan have non-obvious equalities
public override bool Equals(Currency c) {
//2 Kind of currency, dollars and cents.
var amount = this.Amount;
if (this.Currency != "Cents") amount = amount * 100;
var amount2 = c.Amount;
if (c.Currency != "Cents") amount2 = amount2 * 100;
return amount == amount2;
}
GetHashcode is used by things like HashSet and other algorithms that expect Equatable objects.
Tip of the day:
Also provide the == and != methods for your value objects. By default they will check for referential equality and that's not what you case about in case of value objects. And it's just 1 source of errors that you just don't want to have happening.