Во-первых, не забывайте про правило
Equals + GetHashCode. При переопределении Equals следует переопределять GetHashCode.
Во-вторых, переопределять Equals и GetHashCode для изменяемых типов - плохая практика. Всегда есть вероятность, что объект будет использован в HashSet'е или Dictionary, а они требуют неизменности ключа. GetHashCode в идеале должен быть стабильным, то есть
всегда возвращать одинаковое значение.
В третьих (это уже моё субъективное мнение), в большинстве случаев вообще не стоит переопределять эти методы. Кроме, может быть, совсем примитивных типов вроде "строка", "комплексное число", "дата" и т.п. То есть, там, где не может быть никаких разночтений.
Объекты бизнес-логики чаще всего могут быть одновременно равны и не равны в разных контекстах сравнения. Например, где-то необходимо сравнить двух пользователей по ФИО, а в другом месте - глубокое сравнение всех полей, в т.ч. телефон и имейл. В первом случае объекты могут быть равны, а во втором различны.
В этом случае стоит написать несколько компараторов, реализовав интерфейс
IEqualityComparer, и передавать нужный компаратор в нужном месте, например, в конструктор Dictionary.