В С# предусмотрены средства для создания пользовательских классов-контейнеров, к внутренним элементам которых можно обращаться при помощи того же оператора индекса, что и к элементам обычного массива встроенных типов. Метод, который обеспечивает такую возможность, получил название индексатора (indexer). public class CarApp { public static void Main() { Cars carLot = new Cars(); carLot[0] = new Car("FeeFee“, 200, 0); carLot[1] = new Car("BClunker“, 90, 0); carLot[2] = new Car("Zippy“, 30, 0): for(int i = 0; i < 3: i++) { Console.WriteLine("Car number {0}:", i); Console.WriteLine("Name: {0} ", carLot[i].PetName); Console.WriteLine("Max speed: { 0 } " , carLot[i].MaxSpeed); } } } В простейшем виде индексатор создается при помощи синтаксиса this[]. public Car this[int pos] { get { if (pos < 0 || pos > 10) throw new IndexOutOfRangeExceptlon("Out of range!"); else return (carArray[pos]): } set { carArray[pos] = value: } } } За исключением применения ключевого слова t h i s, индексатор ничем не отличается от обычного объявления свойства С#. Обратите внимание, что индексатор не обеспечивает никаких характерных для массивов С# возможностей, не считая применения оператора индекса. Например, мы не сможем воспользоваться имеющимся у каждого массива свойством Length: Console. WriteLine("Cars in stock: {0}", carLot. Length); Язык С# позволяет создавать пользовательские классы и структуры, которые будут реагировать по-своему (как мы определим) на встроенные операторы, например на оператор сложения “+”. Этот прием называется перегрузкой операторов. Рассматривать перегрузку операторов мы будем на примере класса Point. public class Point { private int x, y; public Point() {} public Point(int xPos, int yPos) { x = xPos; у = yPos: } public override string ToString() { return "X pas: " +this.x + "Y pos: " + this.y: } } public static int Main(string[] args) { Point ptOne = new Point(100, 100); Point ptTwo = new Point(40, 40); Point bigPoint = ptOne + ptTwo; Console. WrlteLine( "Here is the big point: {0}“, bigPoint.ToString()); return 0; } Чтобы приведенный выше код заработал, осталось переопределить оператор “+”. В С# для этого можно использовать ключевое слово operator. Обратите внимание, что его можно использовать только вместе с ключевым словом static: public class Point { private int x, y; public Point(){}: public Point (int xPos, int yPos) { x = xPos; у = yPos; } // Перегружаем оператор сложения public static Point operator + (Point p1, Point p2) { Point newPoint = new Point(p1.x + p2.x, p1. у + p2.y); return newPoint; } В С# часто возникает необходимость замещать метод System.Object.Equals(), чтобы можно было выполнять сравнения структурных типов. Помимо замещения методов Equals() и GetHashCode(), скорее всего, потребуется заместить также и операторы равенства (= = и !=). public static bool operator ==(Point p1, Point p2) { return pl.Equals(p2); } public static bool operator !=(Point p1, Point p2); { return !p1.Equals(p2); } Обратите внимание, что для перегрузки операторов равенства мы просто передаем выполнение всей необходимой работы замещенному методу Equals(). Теперь, если нам потребуется использовать обновленный класс Point в нашей программе, мы можем сделать это следующим образом: // Применяем перегруженные операторы равенства public static int Main(string[] args) { If (ptOne = = ptTwo) Console.WriteLine("Same values! "); else Console. WriteLine("Nope. different values"); If (ptOne != ptTwo) Console.WriteLine( "These are not equal"); else Console.WriteLine("Same values!"); } Еще один момент, который необходимо обязательно отметить, — С# не позволит вам перегрузить оператор = = без перегрузки оператора ! = или наоборот. Как и в случае с операторами равенства, С# позволяет производить перегрузку операторов сравнения только парами. Первая пара — это операторы < и >, а вторая — <= и >=. public class Car : IComparable public int CompareTo(object o) { Car temp = (Car)o; if (this.CarID > temp.CarID) return 1; if (this.CarID < temp.CarID) return -1; else return 0; } public static bool operator < (Car c1, Car c2) { IComparable itfComp = (IComparable)c1; return (itfComp. CompareTo(c2) < 0); } public static bool operator > (Car c1, Car c2) { (Comparable itfComp = (IComparable)cl; return (itfComp. CompareTo(c2) > 0); } public static bool operator <= (Car c1, Car c2) { IComparable itfCornp = (IComparable)cl; return (itfComp, CompareTo(c2) <= 0); } public static bool operator >= (Car c1. Car c2) IComparable itfComp = (IComparable)c1; return (itfComp. CornpareTo(c2) >= 0); }