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

Преобразование типов

Преобразование типов

Преобразование в Java состоит из неявного или явного сужения или расширения преобразования типа при использовании оператора (). Можно выполнить аналогичное преобразование типа в C#. C# также вводит ряд действенных способов, встроенных в язык, среди них мы выделим упаковку и распаковку.

Так как типы значений являются блоками памяти определенного размера, они прекрасно подходят для целей ускорения. Иногда, однако удобство объектов желательно иметь для типов значений. Упаковка и распаковка предоставляет механизм, который формирует линию соединения между типами значений и ссылочными типами, позволяя преобразовать их в и из объектного типа.

Упаковка объекта означает неявное преобразование любого типа значения в объектный тип. Экземпляр объекта создается и выделяется, а значение из типа значения копируется в новый объект. Здесь приведен пример, показывающий, как упаковка работает в C#:

// BoxEx.cs
public class OverflowEX {
 public static void Main(String[] args) {
  int x = 10;
  Object obj = (Object)x;
  Console.WriteLine(obj);
 }
}

Такой тип функциональности недоступен в Java. Код, представленный ниже не будет компилироваться, так как примитивы не могут преобразовываться в ссылочные типы:

// BoxEx.java
public class BoxEX {
 public static void main(String args[]) {
  int x = 10;
  object obj = (object)x;
  System.out.println(obj);
 }
}

Распаковка является просто преобразованием объектного типа, приводящим значение снова к соответствующему типу значения. Эта функциональность опять же недоступна в Java. Можно изменить предыдущий код для иллюстрации этой концепции. Сразу заметим, что в то время как упаковка является неявным преобразованием типа, распаковка требует явного преобразования типа. Вот новая реализация BoxEx.cs:

// BoxEX.cs
public class OverflowEX {
 public static void Main(String[] args) {
  int x = 10;
  Object, obj = (Object)x;
  Console.WriteLine(obj);
  int у = (int)obj;
  Console.WriteLine(y);
 }
}

Другим эффективным способом C#, предназначенным для преобразования типов, является возможность определить специальные операторы преобразования. Определенные пользователем преобразования выполняются из типа данных в тип, а не из экземпляра в экземпляр, поэтому они должны быть статическими операциями. Можно использовать ключевое слово implicite для объявления определенных пользователем преобразований из одного типа в другой. Предположим, что имеются два класса Man и Car, которые полностью не связаны. Создадим определенное пользователем преобразование, которое переводит один класс в другой. Ниже приведен листинг Man.cs:

public class Man {
 int arms, legs;
 string name;
 public Man(){}
 public int Arms {
  set {
   arms = value;
  }
  get {
   return arms;
  }
 }
 public string Name {
  set {
   name = value;
  }
  get {
   return name;
  }
 }
 public int Legs {
  set {
   legs = value;
  }
  get {
   return legs;
  }
 }
}

Как можно видеть из приведенного примера, класс Man имеет три свойства: можно задать или извлечь Legs, Arms, Name. Ниже представлен листинг класса 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;
 }
}

He существует на самом деле определенных правил о том, что включать в реализацию специального преобразования. Необходимо, однако, сопоставлять как можно больше пар полей данных между двумя операндами. В случае данного примера поле Car.wheel будет сопоставлено с Man.legs, а поле Car.doors с Man.arms. Не существует поля в Car, которое представляет что-нибудь похожее на Man.Name, но это не мешает использовать его. Можно, скажем, сопоставить Car.headlights с длиной строки, которая хранится в Man.name. Любая реализация, которая имеет смысл для программиста, будет приемлема. В этом случае Man.name не сопоставляется с Car.headlights, вместо этого для headlights жестко кодируется 2, когда делается преобразование, и полностью отбрасывается Man.name. Следующий код содержит модификацию класса Car:

public class Car {
 int wheels, doors, headlights;
 public Car(int wheels, int doors, int headlights) {
  this.wheels = wheels;
  this.doors = doors;
  this.headlight = headlights;
 }
 public static implicit operator Car(Man man) {
  return new Car(man.Legs, man.Arms, 2);
 }
 public static explicit operator(Car car) {
  Man man = new Man();
  man.Arms = car.doors;
  man.Legs = car.wheels;
  man.Name = "john";
  return man;
 }
}

Мы добавим также переопределенные версии для методов ToString() обоих классов, чтобы вывести содержимое объекта Car. Это делается так:

// для Man.cs
public override string ToString() {
 return "[arms:" + arms + "|legs:" + legs + "|name:" + name + "]";
}
// для Car.cs
public override string ToString() {
 return "[wheels:" + wheels + "|doors:" + doors + "|headlights:" + headlights + "]";
}

Листинг кода ниже показывает использование специального преобразования:

// BoxEx.cs
public class OverflowEX {
 public static void Main(String[] args) {
  Car car = new Car (4, 5, 2);
  Man man = (Man) car; // использует явное специальное преобразование
  Console.WriteLine("Man - ");
  Console.WriteLine(man);
  Console.WriteLine();
  Car car2 = man; // использует неявное специальное преобразование
  Console.WriteLine("Car - ");
  Console.WriteLine(car2);
 }
}

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

Man -
[arms:5|legs:4|name:john]
Car -
[wheels:4|doors:5|headlights:2]

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


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