Язык программирования C#9 и платформа .NET5
Перегрузка операций эквивалентности
Как упоминалось в главе 6, метод
может быть перегружен для выполнения сравнений на основе значений (а не ссылок) между ссылочными типами. Если вы решили переопределитьSystem.Object.Equals()(часто вместе со связанным методомEquals()), то легко переопределите и операции проверки эквивалентности (System.Object.GetHashCode()и==). Взгляните на обновленный тип!=:Point// В данной версии типа Point также перегружены операции == и !=.public class Point{...public override bool Equals(object o)=> o.ToString() == this.ToString();public override int GetHashCode()=> this.ToString().GetHashCode();// Теперь перегрузить операции == и !=.public static bool operator ==(Point p1, Point p2)=> p1.Equals(p2);public static bool operator !=(Point p1, Point p2)=> !p1.Equals(p2);}Обратите внимание, что для выполнения всей работы в реализациях операций
и==просто вызывается перегруженный метод!=. Вот как теперь можно применять классEquals():Point// Использование перегруженных операций эквивалентности....Console.WriteLine("ptOne == ptTwo : {0}", ptOne == ptTwo);Console.WriteLine("ptOne != ptTwo : {0}", ptOne != ptTwo);Console.ReadLine();Как видите, сравнение двух объектов с использованием хорошо знакомых операций
и==выглядит намного интуитивно понятнее, чем вызов метода!=. При перегрузке операций эквивалентности для определенного класса имейте в виду, что C# требует, чтобы в случае перегрузки операцииObject.Equals()обязательно перегружалась также и операция==(компилятор напомнит, если вы забудете это сделать).!=Перегрузка операций сравнения
В главе 8 было показано, каким образом реализовывать интерфейс
для сравнения двух похожих объектов. В действительности для того же самого класса можно также перегрузить операции сравнения (IComparable,<,>и<=). Как и в случае операций эквивалентности, язык C# требует, чтобы при перегрузке операции>=обязательно перегружалась также операция<. Если класс>перегружает указанные операции сравнения, тогда пользователь объекта может сравнивать объектыPoint:Point// Использование перегруженных операций < и >....Console.WriteLine("ptOne < ptTwo : {0}", ptOne < ptTwo);Console.WriteLine("ptOne > ptTwo : {0}", ptOne > ptTwo);Console.ReadLine();Когда интерфейс
(или, что еще лучше, его обобщенный эквивалент) реализован, перегрузка операций сравнения становится тривиальной. Вот модифицированное определение класса:IComparable// Объекты Point также можно сравнивать посредством операций сравнения.public class Point : IComparable<Point>{...public int CompareTo(Point other){if (this.X > other.X && this.Y > other.Y){return 1;}if (this.X < other.X && this.Y < other.Y){return -1;}return 0;}public static bool operator <(Point p1, Point p2)=> p1.CompareTo(p2) < 0;public static bool operator >(Point p1, Point p2)=> p1.CompareTo(p2) > 0;public static bool operator <=(Point p1, Point p2)=> p1.CompareTo(p2) <= 0;public static bool operator >=(Point p1, Point p2)=> p1.CompareTo(p2) >= 0;}Финальные соображения относительно перегрузки операций
Как уже упоминалось, язык C# предоставляет возможность построения типов, которые могут уникальным образом реагировать на разнообразные встроенные хорошо известные операции. Перед добавлением поддержки такого поведения в классы вы должны удостовериться в том, что операции, которые планируется перегружать, имеют какой-нибудь смысл в реальности.
Например, пусть перегружена операция умножения для класса
, представляющего минивэн. Что по своей сути будет означать перемножение двух объектовMiniVan? В нем нет особого смысла. На самом деле коллеги по команде даже могут быть озадачены, когда увидят следующее применение классаMiniVan:MiniVan