Книга: C# для профессионалов. Том II

Перезагрузка

Перезагрузка

В начале важно отметить, что перезагрузка операторов не определена в CLS. Однако CLS обращается к ней, потому что языки, обеспечивающие ее функциональность, делают это способом, который могут понять другие языки. Таким образом, языки, которые не поддерживают перезагрузку операторов, все-таки имеют доступ к базовой функциональности. Java является примером языка, который не поддерживает перезагрузку операторов, — ни одна из концепций, рассмотренных в этом разделе, не может ее использовать. Спецификация среды .NET включает ряд рекомендаций для проведения перезагрузки операторов.

? Определите операторы на типах данных значений, которые логически являются встроенным типом языка (таким, как System.Decimal).

? Используйте методы перезагрузки операторов, включающие только тот класс, на котором определены методы.

? Применяйте соглашения об именах и сигнатурах, описанные в CLS.

? Перезагрузка операторов полезна в случаях, где точно известно, каким будет результат операции.

? Предоставьте альтернативные сигнатуры. Не все языки поддерживают вызов перезагруженных операторов. Поэтому постарайтесь всегда включать вторичный метод с подходящим специфическим для домена именем, который имеет эквивалентную функциональность.

Перезагрузка операторов связана как с определенными пользователем преобразованиями, так и с типом данных, а не с экземпляром. Это означает, что она связана со всем типом данных, а не с каким-то одним экземпляром объекта, то есть операция всегда должна быть static и public.

В нижеследующем примере создается тип данных значения Wheels, который может выполнять перезагруженное сложение с самим собой. Можно отметить частое использование комментариев и тегов типа XML внутри комментариев, они нужны для документации. Документация C# будет обсуждаться ниже в этом приложении:

public struct Wheels {
 int wheel;
 // загрузить начальное значение в wheel
 private Wheels(int initVal); {
  wheel = initVal;
 }
 /// <summary>
 /// показывает внутреннее число wheels
 /// </summary>
 internal int Number {
  set {
   wheel = value;
  }
  get {
   return wheel;
  }
 }
 /// <summary>
 /// возвращает внутреннее число. Если этот метод
 /// не переопределен, то возвращаемой строкой будет тип Two.Wheels.
 /// </ summary >
 /// <returns></returns>
 public override string ToString() {
  return wheel.ToString();
 }
 /// < summary>
 /// выполнить операцию сложения на двух wheels
 /// </summary>
 /// <param name="w1"></param>
 /// <param name="w2"></param>
 /// <returns></returns>
 public static Wheels operator + (Wheels w1, Wheels w2) {
  w1.wheel += w2.wheel; return w1;
 }
 /// <summary>
 /// предоставляет альтернативную функциональность сложения.
 /// отметим, что вторая альтернатива операции сложения
 /// находится не в этой структуре, а в классе car
 /// </summary>
 /// <param name= "w"></param>
 /// <returns></returns>
 public Wheels AddWeels(Wheels w) {
  this.wheel += w.wheel;
  return this;
 }
 /// <summary>
 /// поэтому целые литералы можно неявно преобразовать в wheel
 /// </summary>
 /// <param name="x"></param>
 /// <returns></returns>
 public static implicit operator Wheels(int x) {
  return new Wheels(x);
 }
}

Здесь выделим использование метода AddWheel(), что удовлетворяет рекомендациям об альтернативных сигнатурах. Язык CLS, который не поддерживает перезагрузку операторов, может получить доступ к той же функциональности сложения с помощью этого метода. Фрагмент кода ниже показывает, как может использоваться этот тип данных значения:

public static void Main(String[] args) {
 Wheels front = 2; // неявное преобразование
 Wheels back = 4; // неявное преобразование
 Wheels total = front + back; // перезагруженная версия сложения
 Console.WriteLine(total);
}

Компиляция и выполнение этого кода дадут в результате 6. Можно также изменить тип Car, чтобы разрешить сложение и вычитание из него Wheels. Следующий код показывает изменения, сделанные в классе Car:

public class Car {
 int wheels, doors, headlights;
 public Car(int wheels, int doors, int headlights) {
  this.wheels = wheels;
  this.doors = doors;
  this.headlights = headlights;
 }
 public Car AddWheel(Two.Wheels w) {
  this.wheels += w.Number;
  return this;
 }
 internal int Wheels {
  set {
   wheels = value;
  }
  get {
   return wheels;
  }
 }
 /// <summary>
 /// выполняет операцию сложения на Wheel и Car
 /// </summary>
 /// <param name="c1">car</param>
 /// <param name="w1">wheel</param>
 /// <returns></returns>
 public static Car operator +(Car c1, Wheels w1) {
  c1.Wheels += w1.Number;
  return c1;
 }
 /// <summary>
 /// выполняет операцию вычитания на Wheel и Car
 /// </summary>
 /// <param name="c1">car</param>
 /// <param name="w1">wheel</param>
 /// <returns></returns>
 public static Car operator -(Car c1, Wheels w1) {
  c1.Wheels -= w1.Number;
  return c1;
 }
 public override string ToString() {
  return
   "[wheels = " + wheels + "| doors = " + doors + "|"
   + " headlights = " + headlights + "]";
 }
}

В класс Car также был добавлен метод AddWheel. Представленный далее фрагмент кода проверяет функциональность, только что добавленную в Car:

public static void Main(String[] args) {
 Wheels front = 2;
 Wheels back = 4;
 Wheels total = front + back;
 Car greenFordExpedition = new Car(0, 4, 2);
 Console.WriteLine("initial:t" + greenFordExpedition);
 greenFordExpedition += total;
 Console.WriteLine("after add:t" + greenFordExpedition);
 greenFordExpedition -= front;
 Console.WriteLine("after subtract:t" + greenFordExpedition);
}

Компиляция и выполнение этого кода создадут приведенные ниже результаты:

initial:        CAR-[wheels = 0| doors = 4| headlights = 2 ]
after add:      CAR-[wheels = 6| doors = 4| headlights = 2 ]
after subtract: CAR-[wheels = 4| doors = 4| headlights = 2 ]

Оглавление книги


Генерация: 0.511. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз