Чтобы позволить пользовательскому типу по-своему отвечать на встроенные операции, в C# предлагается ключевое слово operator, которое можно использовать только со
// Более 'интеллектуальный' тип Point.
public struct Point {
…
// перегруженная операция +
public static Point operator+(Point p1, Point p2) { return new Point(p1.x + p2.x, p1.y + p2.y); }
// перегруженная операция -
public static Point operator–(Point p1, Point p2) { return new Point(p1.x – p2.x, p1.y – p2.y); }
}
По логике операция + должна просто возвратить совершенно новый объект Point, полученный в результате суммирования соответствующих полей входных параметров Point. Поэтому, когда вы пишете pt1 + pt2, можете представлять себе следующий скрытый вызов статического метода операции +.
// р3 = Point.операция+(p1, р2)
р3 = p1 + р2;
Точно так же p2 – p2 отображается в следующее.
// р3 = Point.операция-(p1, р2)
р3 = p1 – p2;
Операции += и -=
Если вы изучаете C#, уже имея опыт использования C++, то можете обратить внимание на отсутствие возможности перегрузки операторных сокращений, включающих операцию присваивания (+=, -= и т.д.). Не волнуйтесь, в C# операторные сокращения с присваиванием моделируются автоматически, если тип предполагает перегрузку соответствующей бинарной операции. Поэтому, поскольку структура Point уже использует перегрузку операций + и -, вы можете записать следующее.
// Перегрузка бинарных операций автоматически влечет перегрузку
// операторных сокращений с присваиванием.
static void Main(string[] args) {
// Автоматическая перегрузка +=
Point ptThree = new Point(90, 5);
Console.WriteLine("ptThree = {0}", ptThree);
Console.WriteLine("ptThree +=ptTwo: {0}
// Автоматическая перегрузка -=
Point ptFour = new Point(0, 500);
Console.WriteLine("ptFour = {0}", ptFour);
Console.WriteLine("ptFour -= ptThree: {0}", ptFour -= ptThree);
}
Перегрузка унарных операций
В C# также позволяется перегрузка унарных операций, таких как, например, ++ и --. При перегрузке унарной операции вы тоже должны с помощью ключевого слова operator определить статический метод, но в данном случае передается только один параметр, который должен иметь тип, соответствующий определяющему классу или структуре. Например, если добавить в Point следующие перегруженные операции
public struct Point {
…
// Добавление 1 к поступившему Point.
public static Point operator++(Point p1) { return new Point(p1.x+1, p1.y+1); }
// Вычитание 1 от поступившего Point.
public static Point operator--(Point p1) { return new Point(p1.x-1, p1.y-1); }
}
то вы получите возможность увеличивать или уменьшать на единицу значения X и Y объекта Point, как показано ниже.
static void Main(string[] args) {
…
// Применение унарных операций
Console.WriteLine("++ptFive = {0}", ++ptFive);
Console.WriteLine("--ptFive = {0}", --ptFive);
}
Перегрузка операций проверки на тождественность
Вы можете помнить из материала главы 3, что System.Object.Equals() можно переопределить, чтобы сравнение типов выполнялось на основе значений (а не ссылок). Если вы переопределите Equals() (и связанный с Equals() метод System.Object.GetHashCode()), то будет очень просто задать перегрузку операций проверки на тождественность (== и !=). Для иллюстрации мы рассмотрим обновленный тип Point.
// Такая 'инкарнация' Point задает также перегрузку операций == и !=