Определение подпрограмм неявного преобразования

Определение подпрограмм неявного преобразования

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

static void Main(string[] args) {

 …

 // Попытка выполнить неявное преобразование?

 Square s3;

 s3.Length = 83;

 Rectangle rect2 = s3;

}

Как вы можете догадаться сами, этот программный код скомпилирован не будет, поскольку в нем не предлагается никакой подпрограммы неявного преобразования для типа Rectangle. Тут нас подстерегает "ловушка": в одном и том же типе нельзя определять явные и неявные функции преобразования, не отличающиеся по типу возвращаемого значения или по набору параметров. Может показаться, что это правило является слишком ограничивающим, но не следует забывать о том, что даже если тип определяет подпрограмму неявного преобразования, вызывающая сторона "имеет право" использовать синтаксис явного преобразования!

Запутались? Чтобы прояснить ситуацию, добавим в структуру Rectangle подпрограмму неявного преобразования, используя ключевое слово C# implicit (в следующем программном коде предполагается, что ширина результирующего Rectangle получается с помощью умножения стороны Square на 2).

public struct Rесtangle {

 …

 public static implicit operator Rectangle(Square s) {

  Rectangle r;

  r.Height = s.Length;

  // Ширина нового прямоугольника равна

  // удвоенной длине стороны квадрата.

  r.Width = s.Length * 2;

 }

}

С такими изменениями вы получаете возможность преобразовывать указанные типы так.

static void Main(string[] args) {

 …

 // Неявное преобразование: все OK!

 Square s3;

 s3.Length = 83;

 Rectangle rect2 = s3;

 Console.WriteLine("rect2 = {0}", rect2);

 DrawSquare(s3);

 // Синтаксис явного преобразования: тоже OK!

 Square s4;

 S4.Length = 3;

 Rectangle rect3 = (Rectangle)s4;

 Console.WriteLine("rect3 = {0}", rect3);

 …

}

Снова подчеркнем, что допускается определение подпрограмм и явного, и неявного преобразования для одного и того же типа, но только если отличаются их сигнатуры. Поэтому мы можем обновить Square так, как показано ниже.

public struct Square {

 …

 // Можно вызывать как Square sq2 = (Square)90;

 // или как Square sq2 = 90;

 public static implicit operator Square(int sideLength) {

  Square newSq;

  newSq.Length = sideLength;

  return newSq;

  // Должно вызываться как int side = (Square)mySquare;

  public static explicit operator int(Square s) { return s.Length; }

 }

}