В синтаксисе нестандартного преобразования применяется ключевое слово
operator.
public static implicit operator
резулътирующий_тип ( исх_тип операнд);
public"static explicit operator
результирующий_mun
(
ucxjnun операнд).
Правил, связанных с синтаксисом преобразований, немного.
Когда я впервые читал эти правила, у меня было смутное представление о том, что делать дальше. Чтобы в этом разобраться, рассмотрим пример. У нас есть две структуры
(Celsius
и
Fahrenheit),
позволяющие клиенту преобразовывать значение типа
float
в любую температурную шкалу. Сначала я представлю структуру
Celsius
и сделаю несколько замечаний, а затем вы увидите законченное работающее приложение.
struct Celsius {
public Celsius(float temp)
{
this.temp = temp;
}
public static implicit operator Celsius(float temp) {
Celsius c;
с = new Celsius(temp);
return(c); }
public static implicit operator float(Celsius c) {
return((((c.temp - 32) / 9) * 5)); }
public float temp; }
Первое, на что нужно обратить внимание, — использование структуры вместо класса. У меня не было на это особых причин, если не считать, что применение классов обходится дороже (если говорить о выделяемых ресурсах) и что здесь нет особой нужды в использовании класса, так как структуре
Celsius
не нужны какие-то специфические функции, присущие классам С#, например, наследование.
Далее. Я объявил конструктор с единственным аргументом
типа float.
Это значение хранится в члене-переменной
temp.
А теперь посмотрите на оператор преобразования, следующий за конструктором структуры.
Это метод, который будет вызываться, когда клиент попытается преобразовать число с плавающей точкой к
Celsius
или использовать такое число в методе, где должна быть структура
Celsius.
Этот метод ничего особенного не делает и фактически представляет собой шаблон, который можно применять в большинстве основных преобразований. Здесь я создаю экземпляр структуры
Celsius
и возвращаю эту структуру. В последнем методе просто производится преобразование из шкалы Фаренгейта в шкалу Цельсия.
Вот законченное приложение, включая структуру
Fahrenheit.
using System;
struct Celsius {
public Celsius(float temp)
{
this.temp = temp;
}
public static implicit operator Celsius(float temp) {
Celsius c;
с = new Celsius(temp);
return(c); }
public static implicit operator float(Celsius c)
{
return((((c.temp - 32) / 9) * 5)); }
public float temp; }
struct Fahrenheit {
public Fahrenheit(float temp)
<
this.temp = temp; >
public static implicit operator Fahrenheit(float temp) {
Fahrenheit f; f = new Fahrenheit(temp); return(f); }
public static implicit operator float(Fahrenheit f)
{
return((((f.temp • 9) / 5) + 32));
>
public float temp; }
class TemplApp
{
public static void Main()
<
float t;
t=98.6F;
Console.Мг11е("Преобразование {0} в градусы Цельсия = ", t);
Console.WriteLine((Celsius)t);
t=OF;
Console.Write("npeo6pa3oeaHne {0} в градусы
Фаренгейта = ", t); Console.WriteLine((Fahrenheit)t); > }
Скомпилировав и запустив это приложение, вы получите:
Преобразование 98.6 в градусы Цельсия = 37 Преобразование 0 в градусы Фаренгейта = 32
Все это неплохо работает, и выражение
(Celsius)98.6F
понятней, чем вызов статического метода класса. Но учтите, что преобразующему методу можно передавать только значения типа
float.
Например, этот код скомпилирован не будет:
Celsius с = new Celsius(55); Console.WriteLine((Fahrenheit)c);
Кроме того, поскольку отсутствует метод для преобразования в шкалу Цельсия, который принимал бы структуру
Fahrenheit
(и наоборот), код предполагает, что полученное значение требует преобразования. Словом, если я вызову
(Celsius)98.6F, я
получу значение 37. Однако если значение затем снова передать преобразующему методу, он не будет знать, что оно уже преобразовано и логически уже представляет температуру по Цельсию — для преобразующего метода это всего лишь число с плавающей точкой. В результате значение снова будет преобразовано. Следовательно, нам нужно изменить приложение, чтобы каждая из структур принимала в качестве допустимого аргумента другую структуру.
Когда я задумал это сделать, мне стало страшно: я подумал, что это очень сложная задача. И зря! Смотрите, как все просто:
using System;
class Temperature {
public Temperature(float Temp)
<
this.temp = Temp;
}
protected float temp; public float Temp <
get {
return this.temp; } } }
class Celsius ; Temperature {
public Celsius(float Temp) : base(Temp) {}
public static implicit operator Celsius(float Temp) {
return new Celsius(Temp); }
public static implicit operator Celsius(Fahrenheit F) {
return new Celsius(F.Temp);
}
public static implicit operator float(Celsius C)
{
return((((C.temp - 32) / 9) * 5));
} }
class Fahrenheit : Temperature
{
public Fahrenheit(float Temp) : base(Temp) {}
public static implicit operator Fahrenheit(float Temp)
{
return new Fahrenheit(Temp);
}
public static implicit operator Fahrenheit(Celsius C)
{
return new Fahrenheit(C.Temp);
}
public static implicit operator float(Fahrenheit F)
{
return((((F.temp * 9) / 5) + 32));
} }
class Temp2App
{
public static void DisplayTemp(Celsius Temp)
{
Console.Write("Преобразование {0} {1} в градусы "+ "Фаренгейта = ", Temp.ToStringO, Temp.Temp); Console.WriteLine((Fah renheit)Temp); }
public static void DisplayTemp(Fahrenheit Temp)
{
Console.Write("Преобразование {0} {1} в градусы Цельсия = ",
Temp.ToStringO, Temp.Temp); Console.WriteLine((Celsius)Temp); }
public static void Main() {
Fahrenheit f = new Fahrenheit(98.6F);
DisplayTemp(f);
Celsius с = new Celsius(OF); DisplayTemp(c); } }
Обратите внимание: я изменил типы
Celsius
и
Fahrenheit
из
struct в class.
Это сделано только для того, чтобы иметь два примера: один со структурами, другой — с классами. Но более важная причина — возможность совместного использования члена
temp,
имея классы
Celsius
и
Fahrenheit,
производные от одного базового класса
Temperature.
При выводе я здесь применяю унаследованный от
System. Object
метод
ToString.
Кроме того, я добавил преобразование из одной температурной шкалы в другую. Посмотрите, как похожи оба метода преобразования в градусы Цельсия:
public static implicit operator Celsius(float temp) {
Celsius c;
с = new Celsius(temp);
return(c); }
public static implicit operator Celsius(Fahrenheit f) {
Celsius c;
с = new Celsius(f.temp);
return(c); }
Все, что нужно было сделать, — изменить передаваемый аргумент и получать температуру из передаваемого объекта, а не из жестко заданного значения
типа float.
Теперь вы видите, насколько просты и стереотипны методы преобразования.