Минимальный код для равенства в C#

В этой статье Эрик Липперт предлагает в пункте 9, что в C# "слишком много равенства". Он указывает, что существует 9 или 10 различных методов или операторов, которые могут быть перегружены для обеспечения равенства объектов.

Мой первый вопрос: если метод Object.Equals(object) переопределен, то может ли компилятор вызвать любой из других операторов равенства, таких как ==,!=, <= И т. Д., Без кода, который явно выполняет эту операцию??

В C++ есть прецедент для такого поведения. Конструктор копирования может вызываться компилятором в определенных местах, где необходимо создать временную переменную. Я по крайней мере на 95% уверен, что это не может произойти в C#, но это действительно зависит от того, как построен компилятор, и, возможно, от крайних случаев.

Второй вопрос: если компилятор никогда не будет вызывать какой-либо из операторов равенства косвенно, то для небольшого, среднего или даже большого проекта было бы хорошо указать, что для метода будут использоваться только метод Object.Equals(object) и IEquatable Тестирование на равенство и IComparable используется, если тип будет использоваться для сортировки или в других случаях, когда определение ранга объектов необходимо? Другими словами - можно ли избегать определения других операторов равенства, если все участники проекта согласны с тем, что они не будут использоваться и поэтому не нужны?

Предположим, что код должен использоваться только внутри проекта и не будет экспортироваться для использования третьими лицами.

2 ответа

Решение

если Object.Equals(object) метод переопределен, возможно ли, чтобы компилятор вызывал любой из других операторов равенства, таких как ==, !=, <=и т.д. без кода, который явно выполняет эту операцию?

Компилятор C# понятия не имеет, что Equals а также == семантически одинаковы. Если вы позвоните Equals тогда этот метод будет вызван.

тогда для небольшого, среднего или даже большого проекта было бы хорошо указать, что только Object.Equals(object) метод и IEquatable быть использованы для проверки на равенство, и IComparable используется, если тип будет использоваться для сортировки или в других случаях, когда определение ранга объектов необходимо? Другими словами - можно ли избегать определения других операторов равенства, если все участники проекта согласны с тем, что они не будут использоваться и поэтому не нужны?

Опасность, с которой вы столкнетесь здесь, состоит в том, что вы получите == определенный для вас оператор, который по умолчанию ссылается на равенство. Вы можете легко оказаться в ситуации, когда перегружен Equals метод ценит равенство и == ссылается на равенство, а затем вы случайно используете равенство ссылок на вещи, не равные ссылкам, которые равны по значению. Это склонная к ошибкам практика, которую трудно обнаружить с помощью анализа человеческого кода.

Пару лет назад я работал над алгоритмом статического анализа для статистического обнаружения этой ситуации, и мы обнаружили, что частота дефектов составляет около двух экземпляров на миллион строк кода во всех изученных нами базах кода. При рассмотрении только кодовых баз, которые были где-то переопределены EqualsДефект был явно значительно выше!

Кроме того, рассмотрите затраты против рисков. Если у вас уже есть реализации IComparable тогда написание всех операторов - это тривиальные однострочные, которые не будут содержать ошибок и никогда не будут изменены. Это самый дешевый код, который вы когда-либо будете писать. Если бы у меня был выбор между фиксированной стоимостью написания и тестирования дюжины крошечных методов по сравнению с неограниченной стоимостью поиска и исправления трудно видимой ошибки, в которой вместо равенства значений используется равенство ссылок, я знаю, какой из них я бы выбрал.

Мой первый вопрос: если метод Object.Equals(object) переопределен, то может ли компилятор вызвать любой из других операторов равенства, таких как ==,!=, <= И т. Д., Без кода, который явно выполняет эту операцию??

Не то, что я знаю из.

Второй вопрос: если компилятор никогда не будет вызывать какой-либо из операторов равенства косвенно, то для небольшого, среднего или даже большого проекта было бы хорошо указать, что для метода будут использоваться только метод Object.Equals(object) и IEquatable Тестирование на равенство и IComparable используется, если тип будет использоваться для сортировки или в других случаях, когда определение ранга объектов необходимо? Другими словами - можно ли избегать определения других операторов равенства, если все участники проекта согласны с тем, что они не будут использоваться и поэтому не нужны?

Технически, то, что вы предлагаете, возможно. Но на практике я бы даже не поверил, что буду следовать установленным нормам, даже если бы я был единственным, кто работал над проектом. Я также буду волноваться за каждый вызов метода LINQ, который я делаю: как этот метод LINQ работает под прикрытием? Нужно ли это IEquatable? Использует ли это IComparable? Здесь я в безопасности?

Если бы я попытался применить подобный подход к тому, что вы предлагаете, я бы, вероятно, все еще заставил бы мой класс реализовать все соответствующие интерфейсы равенства, но методы бросили бы NotSupportedException исключение по умолчанию. Таким образом, по крайней мере, я буду чувствовать, что у меня есть сеть безопасности на случай, если я по ошибке использую неправильный метод, или если я использую библиотечный метод, который опирается на другой интерфейс равенства.

Другие вопросы по тегам