Содержание
Операторы могут быть перегружены, чтобы обеспечить более естественный синтаксис для пользовательских типов. В большей степени это актуально для реализации пользовательских структур, представляющих довольно простые типы данных.
Перегружены могут быть следующие операторы:
+ - * / ++ -- ! ~ % & | ^ == != < << >> >
а также операторы автоматического и явного приведения (с помощью ключевых слов 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.

