Equals and GetHashCode
Remarks
Each implementation of Equals
must fulfil the following requirements:

Reflexive: An object must equal itself.
x.Equals(x)
returnstrue
. 
Symmetric: There is no difference if I compare x to y or y to x  the result is the same.
x.Equals(y)
returns the same value asy.Equals(x)
. 
Transitive: If one object is equal to another object and this one is equal to a third one, the first has to be equal to the third.
if(x.Equals(y) && y.Equals(z))
returnstrue
, thenx.Equals(z)
returnstrue
. 
Consistent: If you compare an object to another multiple times, the result is always the same.
Successive invocations ofx.Equals(y)
return the same value as long as the objects referenced by x and y are not modified. 
Comparison to null: No object is equal to
null
.x.Equals(null)
returnsfalse
.
Implementations of GetHashCode
:

Compatible with
Equals
: If two objects are equal (meaning thatEquals
returns true), thenGetHashCode
must return the same value for each of them. 
Large range: If two objects are not equal (
Equals
says false), there should be a high probability their hash codes are distinct. Perfect hashing is often not possible as there is a limited number of values to choose from. 
Cheap: It should be inexpensive to calculate the hash code in all cases.
See: Guidelines for Overloading Equals() and Operator ==
Default Equals behavior.
Equals
is declared in the Object
class itself.
By default, Equals
has the following behavior:

If the instance is a reference type, then
Equals
will return true only if the references are the same. 
If the instance is a value type, then
Equals
will return true only if the type and value are the same. 
string
is a special case. It behaves like a value type.
Equals and GetHashCode in IEqualityComparator
For given type Person
:
But defining Equals
and GetHashCode
into an IEqualityComparator
:
Note that for this query, two objects have been considered equal if both the Equals
returned true and the GetHashCode
have returned the same hash code for the two persons.
Override Equals and GetHashCode on custom types
For a class Person
like:
But defining Equals
and GetHashCode
as follows:
Also using LINQ to make different queries on persons will check both Equals
and GetHashCode
:
Writing a good GetHashCode override
GetHashCode
has major performance effects on Dictionary<> and HashTable.
Good GetHashCode
Methods
 should have an even distribution
 every integer should have a roughly equal chance of returning for a random instance
 if your method returns the same integer (e.g. the constant '999') for each instance, you'll have bad performance
 should be quick
 These are NOT cryptographic hashes, where slowness is a feature
 the slower your hash function, the slower your dictionary
 must return the same HashCode on two instances that
Equals
evaluates to true if they do not (e.g. because
GetHashCode
returns a random number), items may not be found in aList
,Dictionary
, or similar.
 if they do not (e.g. because
A good method to implement GetHashCode
is to use one prime number as a starting value, and add the hashcodes of the fields of the type multiplied by other prime numbers to that:
Only the fields which are used in the Equals
method should be used for the hash function.
If you have a need to treat the same type in different ways for Dictionary/HashTables, you can use IEqualityComparer.