Перегрузка операций преобразования типов

Последнее обновление: 28.12.2021

В прошлой теме была рассмотрена тема перегрузки операторов. И с этой темой тесно связана тема перегрузки операторов преобразования типов.

Ранее мы рассматривали явные и неявные преобразования примитивных типов. Например:

int x = 50;
byte y = (byte)x; // явное преобразование от int к byte
int z = y;  // неявное преобразование от byte к int

И было бы не плохо иметь возможность определять логику преобразования одних типов в другие. И с помощью перегрузки операторов мы можем это делать. Для этого в классе определяется метод следующей формы:

public static implicit|explicit operator Тип_в_который_надо_преобразовать(исходный_тип param)
{
	// логика преобразования
}

После модификаторов public static идет ключевое слово explicit (если преобразование явное, то есть нужна операция приведения типов) или implicit (если преобразование неявное). Затем идет ключевое слово operator и далее возвращаемый тип, в который надо преобразовать объект. В скобках в качестве параметра передается объект, который надо преобразовать.

Например, пусть у нас есть следующий класс Counter, который представляет счетчик-секундомер и который хранит количество секунд в свойстве Seconds:

class Counter
{
	public int Seconds { get; set; }

	public static implicit operator Counter(int x)
	{
		return new Counter { Seconds = x };
	}
	public static explicit operator int(Counter counter)
	{
		return counter.Seconds;
	}
}

Первый оператор преобразует число - объект типа int к типу Counter. Его логика проста - создается новый объект Counter, у которого устанавливается свойство Seconds.

Второй оператор преобразует объект Counter к типу int, то есть получает из Counter число.

Примение операторов преобразования в программе:

Counter counter1 = new Counter { Seconds = 23 };

int x = (int)counter1;
Console.WriteLine(x);   // 23

Counter counter2 = x;
Console.WriteLine(counter2.Seconds);  // 23

Поскольку операция преобразования из Counter в int определена с ключевым словом explicit, то есть как явное преобразование, то в этом случае необходимо применить операцию приведения типов:

int x = (int)counter1;

В случае с операцией преобразования от int к Counter ничего подобного делать не надо, поскольку данная операция определена с ключевым словом implicit, то есть как неявная. Какие операции преобразования делать явными, а какие неявные, в данном случае не столь важно, это решает разработчик по своему усмотрению.

Следует учитывать, что оператор преобразования типов должен преобразовывать из типа или в тип, в котором этот оператор определен. То есть оператор преобразования, определенный в типе Counter, должен либо принимать в качестве параметра объект типа Counter, либо возвращать объект типа Counter.

Рассмотрим также более сложные преобразования, к примеру, из одного составного типа в другой составной тип. Допустим, у нас есть еще класс Timer:

class Timer
{
	public int Hours { get; set; }
	public int Minutes { get; set; }	
	public int Seconds { get; set; }
}
class Counter
{
	public int Seconds { get; set; }

	public static implicit operator Counter(int x)
	{
		return new Counter { Seconds = x };
	}
	public static explicit operator int(Counter counter)
	{
		return counter.Seconds;
	}
	public static explicit operator Counter(Timer timer)
	{
		int h = timer.Hours * 3600;
		int m = timer.Minutes * 60;
		return new Counter { Seconds = h + m + timer.Seconds };
	}
	public static implicit operator Timer(Counter counter)
	{
		int h = counter.Seconds / 3600;
		int m = (counter.Seconds % 3600) / 60;
		int s = counter.Seconds % 60;
		return new Timer { Hours = h, Minutes = m, Seconds = s };
	}
}

Класс Timer представляет условный таймер, который хранит часы, минуты и секунды. Класс Counter представляет условный счетчик-секундомер, который хранит количество секунд. Исходя из этого мы можем определить некоторую логику преобразования из одного типа к другому, то есть получение из секунд в объекте Counter часов, минут и секунд в объекте Timer. Например, 3675 секунд по сути это 1 час, 1 минута и 15 секунд

Применение операций преобразования:

Counter counter1 = new Counter { Seconds = 115 };

Timer timer = counter1;
Console.WriteLine($"{timer.Hours}:{timer.Minutes}:{timer.Seconds}"); // 0:1:55

Counter counter2 = (Counter)timer;
Console.WriteLine(counter2.Seconds);  //115
Дополнительные материалы
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850