Пока я изучал C #, я обнаружил, что C # поддерживает перегрузку операторов. У меня проблема с хорошим примером, который:
- Имеет смысл (например, добавление класса с именем овец и коров)
- Не является примером объединения двух строк
Примеры из библиотеки базовых классов приветствуются.
==
для умножения, это имеет смысл для меня, но может не иметь смысла для других! Это вопрос о легитимности языков программирования какого-либо объекта или мы говорим о «лучших методах кодирования»?Ответы:
Очевидными примерами соответствующей перегрузки операторов являются любые классы, которые ведут себя так же, как и числа. Таким образом, классы BigInt (как предлагает Джалайн ), комплексные числа или матричные классы (как предполагает Superbest ) имеют те же операции, что и обычные числа, поэтому очень хорошо отображаются на математические операторы, в то время как операции времени (как предлагает svick ) отображаются на подмножество из этих операций.
Чуть более отвлеченно, операторы могут быть использованы при выполнении набора как операций, так
operator+
может быть союз ,operator-
может быть дополнением и т.д. Это действительно начинает растягиваться парадигму , хотя, особенно если вы используете сложение или умножения оператора на операцию , которая ISN» т коммутативный , как вы могли бы ожидать, что они будут.Сам C # имеет отличный пример перегрузки нечисловых операторов. Он использует
+=
и-=
для добавления и вычитания делегатов , т.е. регистрирует и отменяет их регистрацию. Это хорошо работает , потому что+=
и-=
операторы работают , как можно было бы ожидать их к, и этот результат в гораздо более лаконичном коде.Для пуриста одна из проблем со строковым
+
оператором состоит в том, что он не коммутативный."a"+"b"
это не то же самое, что"b"+"a"
. Мы понимаем это исключение для строк, потому что оно очень распространено, но как мы можем определить, будет ли использованиеoperator+
других типов коммутативным или нет? Большинство людей предполагают, что это так, если только объект не похож на строку , но вы никогда не знаете, что люди примут.Как и со строками, слабые стороны матриц также довольно хорошо известны. Очевидно, что
Matrix operator* (double, Matrix)
это скалярное умножение, тогда как, например,Matrix operator* (Matrix, Matrix)
это будет матричное умножение (т. Е. Матрица умножения на скалярное произведение).Точно так же использование операторов с делегатами настолько очевидно далеко от математики, что вы вряд ли допустите эти ошибки.
Кстати, на конференции ACCU 2011 года Роджер Орр и Стив Лав представили сессию, посвященную тому, что некоторые объекты более равны, чем другие, - взгляд на многие значения равенства, ценности и идентичности . Их слайды можно загрузить , как и Приложение Ричарда Харриса о равенстве с плавающей точкой . Резюме: будь очень осторожен с
operator==
драконами!Перегрузка операторов является очень мощной семантической техникой, но ее легко использовать. В идеале вы должны использовать его только в ситуациях, когда из контекста очень ясно, каково влияние перегруженного оператора. Во многих отношениях
a.union(b)
это яснее , чемa+b
иa*b
является гораздо более неясным , чемa.cartesianProduct(b)
, тем более , что результат декартова произведения будет ,SetLike<Tuple<T,T>>
а неSetLike<T>
.Реальные проблемы с перегрузкой операторов возникают, когда программист предполагает, что класс будет вести себя одинаково, но на самом деле он ведет себя по-другому. Такого рода семантическое столкновение - это то, что я предлагаю, важно избегать.
источник
d1 + d2
для любых двух делегатов одного типа.Я удивлен, что никто не упомянул один из наиболее интересных случаев в BCL:
DateTime
иTimeSpan
. Вы можете:TimeSpan
с, чтобы получить другойTimeSpan
TimeSpan
чтобы получить отрицательныйTimeSpan
DateTime
с, чтобы получитьTimeSpan
TimeSpan
из,DateTime
чтобы получить другойDateTime
Другой набор операторов , которые могли бы иметь смысл на многих типов
<
,>
,<=
,>=
. В BCL, например,Version
их реализует.источник
Первый пример, который мне приходит в голову, - это реализация BigInteger , которая позволяет работать с большими целыми числами со знаком. Проверьте ссылку MSDN, чтобы увидеть, сколько операторов было перегружено (то есть, есть большой список, и я не проверял, все ли операторы были перегружены, но это, безусловно, так)
Кроме того, поскольку я также занимаюсь Java, а Java не позволяет перегрузить операторы, писать невероятно сладко
Чем в Java:
источник
Я рад, что увидел это, потому что я дурачился с Иронией, и в ней БОЛЬШОЕ использование перегрузки операторов. Вот пример того, что он может сделать.
Итак, Irony - это «.NET Language реализации Kit» и генератор парсера (генерирующий парсер LALR). Вместо того, чтобы изучать новый синтаксис / язык, такой как генераторы синтаксических анализаторов, такие как yacc / lex, вы пишете грамматику на C # с перегрузкой оператора. Вот простая грамматика БНФ
Так что это простая маленькая грамматика (извините, если есть несоответствия, так как я просто изучаю BNF и строю грамматику). Теперь давайте посмотрим на C #:
Как вы можете видеть, с перегрузкой оператора написание грамматики на C # почти точно написание грамматики на BNF. Для меня это не только имеет смысл, но и позволяет использовать перегрузку операторов.
источник
Ключевым примером является оператор == / operator! =.
Если вы хотите легко сравнить два объекта по значениям данных, а не по ссылкам, вам нужно перегрузить .Equals (and.GetHashCode!) И, возможно, захотите также использовать операторы! = И == для согласованности.
Я никогда не видел диких перегрузок других операторов в C #, хотя (я предполагаю, что есть крайние случаи, где это могло бы быть полезным).
источник
Этот пример из MSDN показывает, как реализовать комплексные числа и заставить их использовать обычный оператор +.
Другой пример показывает, как это сделать для добавления матрицы, а также объясняет, как не использовать ее для добавления автомобиля в гараж (читайте по ссылке).
источник
Хорошее использование перегрузки может быть редким, но это случается.
перегрузка operator == и operator! = показывают две философские мысли: те, кто говорит, что это облегчает задачу, и те, кто не говорит, что это предотвращает сравнение адресов (то есть я указываю на одно и то же место в памяти, а не на одну и ту же копию). объект).
Я считаю, что перегрузка операторов приведения удобна в определенных ситуациях. Например, мне пришлось сериализовать / десериализовать в XML логическое значение, представленное как 0 или 1. Правильный (неявный или явный, я забыл) оператор приведения от логического к int и обратно сделал свое дело.
источник
object.ReferenceEquals()
.==
путем приведения:(object)foo == (object)bar
всегда сравнивает ссылки. Но я бы предпочелReferenceEquals()
, как упоминает @ dan04, потому что это более понятно, что он делает.Они не относятся к той категории вещей, о которой обычно думают люди, когда им приходится перегружать операторы, но я думаю, что одним из наиболее важных операторов, способных перегрузить, является оператор преобразования .
Операторы преобразования особенно полезны для типов значений, которые могут «очищать» от числового типа или могут действовать как числовой тип в некоторых контекстах. Например, вы можете определить специальный
Id
тип, который представляет определенный идентификатор, и вы можете предоставить неявное преобразование в,int
чтобы вы могли передатьId
метод, который принимаетint
, но явное преобразование изint
в,Id
чтобы никто не мог передатьint
в метод, который принимаетId
без приведения его первым.В качестве примера за пределами C # язык Python включает в себя множество специальных поведений, которые реализованы как перегружаемые операторы. К ним относятся
in
оператор для проверки членства,()
оператор для вызова объекта, как будто это функция, иlen
оператор для определения длины или размера объекта.Кроме того, у вас есть языки, такие как Haskell, Scala и многие другие функциональные языки, где такие имена, как
+
обычные функции, а не операторы вообще (и есть языковая поддержка для использования функций в позиции инфикса).источник
Точка Struct в System.Drawing пространстве имен использует перегрузку для сравнения два разных мест , используя перегрузку оператора.
Как видите, намного проще сравнить координаты X и Y двух мест с использованием перегрузки.
источник
Если вы знакомы с математическим вектором, вы можете увидеть использование в перегрузке
+
оператора. Вы можете добавить векторa=[1,3]
сb=[2,-1]
и получитьc=[3,2]
.Перегрузка equals (==) также может быть полезна (хотя, вероятно, лучше реализовать
equals()
метод). Чтобы продолжить векторные примеры:источник
Представьте кусок кода для рисования на форме
Другой распространенный пример - когда структура используется для хранения информации о положении в форме вектора.
только для последующего использования в качестве
источник
operator+
следует не перегружать (вы можете реализовать точку в терминах вектора, но вы не должны быть в состоянии добавить две точки)p1+((p2-p1)+(p3-p1)+(p4-p1))/4
, но это выглядит несколько неловко.