Содержание
Операторы могут быть перегружены, чтобы обеспечить более естественный синтаксис для пользовательских типов. В большей степени это актуально для реализации пользовательских структур, представляющих довольно простые типы данных.
Перегружены могут быть следующие операторы:
+ - * / ++ -- ! ~ % & | ^ == != < << >> >
а также операторы автоматического и явного приведения (с помощью ключевых слов implicit и explicit), литералы true и false, и унарные + и -.
Составные операторы присвоения (например, +=, /=) автоматически переопределяются при переопределении соответствующих не составных операторов (например, +, /).
Операторные методы (Operator Functions)
Перегрузить оператор можно объявив операторный метод. Операторный метод должен быть статическим, и как минимум один из его операндов должен быть того типа, в котором объявлен операторный метод. Объявляется операторный метод с помощью ключевого слова operator:
1 2 3 4 5 6 7 8 9 10 11 12 | public struct Note { int value; public Note (int semitonesFromA) { value = semitonesFromA; } public static Note operator + (Note x, int semitones) { return new Note (x.value + semitones); } } |
В примере описывается структура, представляющая собой музыкальную ноту. С помощью перегруженного оператора + мы можем создать новую ноту:
1 2 | Note B = new Note (2); Note CSharp = B + 2; |
Поскольку оператор + был перегружен, перегружен был и составной оператор +=:
1 | CSharp += 2; |
Перегрузка операторов равенства и сравнения
Операторы равенства и сравнения обычно переопределяются для структур, реже для классов. При перегрузке этих операторов необходимо соблюдать несколько правил:
- Парность операторов: операторы, представляющие логическую пару: (
== !=), (< >),
and (<= >=), перегружаются одновременно (т.е. если перегружен один оператор, второй автоматически считается также перегруженным). EqualsиGetHashCode: при перегрузке операторов==и!=, также необходимо переопределить методыEqualsиGetHashCode(определены дляobject), чтобы коллекции и хэштаблицы могли корректно работать с типом.IComparableиIComparable<T>: при перегрузке операторов<и>как правило необходимо реализовывать интерфейсыIComparableиIComparable<T>.
В продолжение примера структуры Note:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static bool operator == (Note n1, Note n2) { return n1.value == n2.value; } public static bool operator != (Note n1, Note n2) { return !(n1.value == n2.value); } public override bool Equals (object otherNote) { if (!(otherNote is Note)) return false; return this == (Note)otherNote; } public override int GetHashCode() { return value.GetHashCode(); // Use value's hashcode } |
Автоматическое и явное преобразование
Автоматическое и явное преобразование могут быть перегружены также как операторы. Перегрузка преобразований типов обычно используется для того, чтоб сделать ее более лаконичной и естественной для связанных типов.
В следующем примере объявляется преобразование между структурой Note (из примера выше) и типом double (представляющим частоту ноты в герцах):
1 2 3 4 5 6 7 8 9 10 11 12 13 | // преобразование в герцы public static implicit operator double (Note x) { return 440 * Math.Pow (2,(double) x.value / 12 ); } // преобразование из герц public static explicit operator Note (double x) { return new Note ((int) (0.5 + 12 * (Math.Log(x/440) / Math.Log(2)) )); } ... Note n =(Note)554.37; // явное приведение double x = n; // автоматическое преобразование |
Переопределенные преобразования игнорируются операторами as и is.

