Перегрузка оператора c помощью интерфейсного программирования в C#



фон



Я использую программирование на основе интерфейса в текущем проекте и столкнулся с проблемой при перегрузке операторов (в частности, операторов равенства и неравенства).





предположения




  • я использую C# 3.0, .NET 3.5 и Visual Studio 2008


обновление - следующее предположение было ложным!




  • требуется, чтобы все сравнения использовали Equals, а не operator== не является жизнеспособное решение, особенно при передаче типов в библиотеки (например, коллекции).


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




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




и Equatable Интерфейс




интерфейс IEquatable используется универсальными объектами коллекции, такими как Словарь, Список и LinkedList при тестировании на равенство в таких методах, как Contains, IndexOf, LastIndexOf и Remove. Он должен быть реализован для любого объекта, который может храниться в родовой коллекция.






ограничения




  • любое решение не должно требовать приведения объектов от их интерфейсов к их конкретным типам.



697   2  

2 ответов:

короткий ответ: я думаю, что ваше второе предположение может быть ошибочным. Equals() Это правильный способ проверить семантического равенства из двух объектов, не operator ==.


длинный ответ: разрешение перегрузки операторов выполняется во время компиляции, а не выполнения.

если компилятор не может точно знать типы объектов, к которым он применяет оператор, он не будет компилироваться. Так как компилятор не может быть уверен, что это IAddress будет что-то, что имеет переопределение для == определено, он возвращается к значению по умолчанию operator == реализация System.Object.

чтобы увидеть это более четко, попробуйте определить operator + на Address и добавить два IAddress экземпляров. если вы явно не приведете к Address, это не будет компилироваться. Зачем? Потому что компилятор не может сказать, что конкретный IAddress это Address, и нет никакого значения по умолчанию operator + реализация упасть обратно в System.Object.


часть вашего разочарования, вероятно, связана с тем, что Object осуществляет operator ==, и все Object, поэтому компилятор может успешно разрешать такие операции, как a == b для всех типов. Когда вы переехали ==, вы ожидали увидеть такое же поведение, но не сделали, и это потому, что лучшее соответствие компилятор может найти оригинал Object реализация.

требуется, чтобы все сравнения использовали равные rather than operator== не является жизнеспособным решением, особенно при передаче ваших типов в библиотеки (например, коллекции).

на мой взгляд, это именно то, что вы должны делать. Equals() Это правильный способ проверить семантического равенства двух объектов. иногда семантическое равенство-это просто ссылочное равенство, и в этом случае вам не нужно ничего менять. В других случаях, как в вашем примере, вы будете переопределять Equals когда вам нужно сильнее контракта равенство, как равенство ссылок. Например, вы можете рассмотреть два Persons равны, если они имеют один и тот же номер социального страхования, или два Vehicles равны, если у них одинаковый VIN.

но Equals() и operator == не одно и то же. Всякий раз, когда вам нужно переопределить operator ==, вы должны переопределить Equals(), но почти никогда наоборот. operator == это скорее синтаксическое удобство. Некоторые языки CLR (например, Visual Basic.NET) даже не разрешаю вам переопределите оператор равенства.

мы столкнулись с той же проблемой и нашли отличное решение: пользовательские шаблоны Resharper.

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

каталог включал все шаблоны, известные как неправильные в нашей системе:

$i1$ == $i2$ (где i1 и i2 -выражения нашего типа интерфейса, или полученный.

заменить шаблон

$i1$.Equals($i2$)

и серьезность "показать как ошибка".

точно так же у нас $i1$ != $i2$

надеюсь, что это помогает. П. С. глобальные каталоги-это объект для ReSharper 6.1 (ВП), очень скоро будет помечен как окончательный.

обновление: я подал Resharper Issue чтобы отметить весь интерфейс '= = ' предупреждение, если оно не сравнивается с null. Пожалуйста, голосуйте, если вы считаете, что это достойно особенность.

обновление 2: Resharper также имеет атрибут [CannotApplyEqualityOperator], который может помочь.

Comments

    Ничего не найдено.