Минимальный код для равенства в 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
исключение по умолчанию. Таким образом, по крайней мере, я буду чувствовать, что у меня есть сеть безопасности на случай, если я по ошибке использую неправильный метод, или если я использую библиотечный метод, который опирается на другой интерфейс равенства.