While learning .net (by c#) i found 5 ways for checking equality between objects.
Each version of equality is slightly different.
ReferenceEquals tests for reference equality.
virtual Equals by default checks for reference equality for class types and value equality for struct types. It can be overridden to define equality differently, if desired; and should be overridden for value types.
static Equals just calls virtual Equals, but also allows for null arguments.
IEquatable is a generic/type-safe equivalent for virtual Equals.
operator== is intended to be like the default virtual Equals, meaning reference equality for class types (unless the class also overrides other operators). It should also be overridden for value types.
If you write your own collection class, use IEqualityComparer, defaulting to EqualityComparer. Don't use any of the equality comparisons directly.