// Такая 'инкарнация' Point задает также перегрузку операций == и != .
public struct Point {
…
public override bool Equals(object o) {
if (o is Point) {
if (((Point)o).x == this.x && ((Point)о). у == this.y) return true;
}
return false;
}
public override int GetHashCode() { return this.ToString().GetHashCode(); }
// Здесь позволяется перегрузка операций == и !=.
public static bool operator==(Point p1, Point p2) { return p1.Equals(p2); }
public static bool operator!=(Point p1, Point p2) { return!p1.Equals(p2); }
}
Обратите внимание на то, что данная реализация операций == и != просто вызывает переопределенный метод Equals(), который и выполняет основную работу. С учетом этого вы можете теперь использовать свой класс Point так.
// Использование перегруженных операций проверки на тождественность.
static void Main(string[] args) {
…
Console.WriteLine("ptOne == ptTwo: {0}", ptOne == ptTwo);
Console.WriteLine("ptOne != ptTwo: {0}", ptOne != ptTwo);
}
Как видите, здесь два объекта сравниваются с помощью операций == и !=, а не с помощью "менее естественного" вызова Object.Equals(). При использовании перегрузки операций проверки на тождественность для класса имейте в виду, что в C# требуется, чтобы при переопределении операции – обязательно переопределялась и операция != (если вы забудете это сделать, компилятор вам напомнит).
Перегрузка операций сравнения
Из материала главы 7 вы узнали о том, как реализовать интерфейс IComparable, чтобы иметь возможность сравнения подобных объектов. В дополнение к этому для того же класса вы можете использовать перегрузку операций сравнения (‹, ›, ‹= и ›=). Подобно операциям проверки на тождественность, в C# требуется, чтобы при перегрузке ‹ выполнялась и перегрузка ›. Это же касается и операций ‹= и ›=. Если тип Point использует перегрузку операций сравнения, пользователь объекта получает возможность сравнивать объекты Point так, как показано ниже.
// Использование перегруженных операций ‹ и ›.
static void Main(string[] args) {
…
Console.WriteLine("ptOne ‹ ptTwo: {0} ", ptOne ‹ ptTwo);
Console.WriteLine("ptOne › ptTwo: {0}", ptOne › ptTwo);
}
В предположении о том, что интерфейс IComparable реализован, перегрузка операций сравнения оказывается тривиальной. Вот как может выглядеть обновленное определение класса.
// Можно сравнивать объекты Point с помощью операций сравнения.
public struct Point: IComparable {
…
public int CompareTo(object obj) {
if (obj is Point) {
Point p = (Point)obj;
if (this.x › p.x && this.y › p.y) return 1;
if (this.x ‹ p.x && this.y ‹ p.y) return -1;
else return 0;
} else throw new ArgumentException();
}
public static bool operator‹(Point p1, Point p2) { return(p1.CompareTo(р2) ‹ 0); }
public static bool operator›(Point p1, Point p2) { return(p1.CompareTo(p2) › 0); }
public static bool operator‹=(Point p1, Point p2) { return(p1.CompareTo(p2) ‹= 0); }
public statiс bool operator›=(Point p1, Point p2) { return(p1.CompareTo(p2) ›= 0); }
}
Внутреннее представление перегруженных операций
Подобно любому элементу программы C#, перегруженные операции представляются специальными элементами синтаксиса CIL. Откройте, например, компоновочный блок OverloadedOps.exe с помощью ildasm.exe. Как показано на рис. 9.1, перегруженные операции внутри блока представляются скрытыми методами (это, например, op_Addition(), oр_Subtraction(), op_Equality() и т.д.).
Теперь, если рассмотреть CIL-инструкции для метода op_Addition, то вы обнаружите, что csc.exe добавляет в метод ключевое слово specialname.
.method public hidebysig specialnamestatic valuetype OverloadedOps.Point op_Addition(valuetype OverloadedsOps.Point p1, valuetype OverloadedOps.Point p2) cil managed {
…
}
Рис. 9.1. В терминах CIL перегруженные операции отображаются в скрытые методы
Итак, любая операция, допускающая перегрузку, сводится в терминах CIL к специальному именованному методу. В табл. 9.2 раскрывается соответствие имен типичных операций C# и методов CIL.
Таблица 9.2.Соответствие имен операций C# и методов CIL
Внутренняя операция C# |
Представление CIL |
–- |
op_Decrement() |
++ |
op_Increment() |
+ |
op_Addition() |
– |
op_Subtraction() |
* |
op_Multiply() |
/ |
op_Division() |
== |
op_Equality() |
› |
op_GreaterThan() |
‹ |
op_LessThan() |
!= |
op_Inequality() |
›= |
op_GreaterThanOrEqual() |
‹= |
op_LessThanOrEqual() |
–= |
op_SubtractionAssignment() |
+= |
op_AdditionAssignment() |
Использование перегруженных операций в языках, не поддерживающих перегрузку операций
Читать дальше