Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
// Что?! Понять это непросто...
MiniVan newVan = myVan * yourVan;
Перегрузка операций обычно полезна только при построении атомарных типов данных. Векторы, матрицы, текст, точки, фигуры, множества и т.п. будут подходящими кандидатами на перегрузку операций, но люди, менеджеры, автомобили, подключения к базе данных и веб-страницы — нет. В качестве эмпирического правила запомните, что если перегруженная операция затрудняет понимание пользователем функциональности типа, то не перегружайте ее. Используйте такую возможность с умом.
Понятие специальных преобразований типов
Давайте теперь обратимся к теме, тесно связанной с перегрузкой операций, а именно — к специальным преобразованиям типов. Чтобы заложить фундамент для последующего обсуждения, кратко вспомним понятие явных и неявных преобразований между числовыми данными и связанными типами классов.
Повторение: числовые преобразования
В терминах встроенных числовых типов (
sbyte
int
float
int a = 123;
long b = a; // Неявное преобразование из int в long.
int c = (int) b; // Явное преобразование из long в int.
Повторение: преобразования между связанными типами классов
В главе 6 было показано, что типы классов могут быть связаны классическим наследованием (отношение "является"). В таком случае процесс преобразования C# позволяет осуществлять приведение вверх и вниз по иерархии классов. Например, производный класс всегда может быть неявно приведен к базовому классу. Тем не менее, если вы хотите сохранить объект базового класса в переменной производного класса, то должны выполнить явное приведение:
// Два связанных типа классов.
class Base{}
class Derived : Base{}
// Неявное приведение производного класса к базовому.
Base myBaseType;
myBaseType = new Derived();
// Для сохранения ссылки на базовый класс в переменной
// производного класса требуется явное преобразование.
Derived myDerivedType = (Derived)myBaseType;
Продемонстрированное явное приведение работает из-за того, что классы
Base
Derived
myBaseType
Derived
myBaseType
Base
InvalidCastException
as
// Неявное приведение производного класса к базовому.
Base myBaseType2 = new();
// Сгенерируется исключение InvalidCastException :
// Derived myDerivedType2 = (Derived)myBaseType2 as Derived;
// Исключения нет, myDerivedType2 равен null:
Derived myDerivedType2 = myBaseType2 as Derived;
Но что если есть два типа классов в разных иерархиях без общего предка (кроме
System.Object
В качестве связанного замечания обратимся к типам значений (структурам). Предположим, что имеются две структуры с именами
Square
Rectangle
Несмотря на то что в структурах можно было бы создать вспомогательные методы (наподобие
Rectangle.ToSquare()
()
// Преобразовать Rectangle в Square!
Rectangle rect = new Rectangle
{
Width = 3;
Height = 10;
}
Square sq = (Square)rect;
Создание специальных процедур преобразования
Начните с создания нового проекта консольного приложения по имени
CustomConversions
explicit
implicit
using System;
namespace CustomConversions
{
public struct Rectangle
{
public int Width {get; set;}
public int Height {get; set;}
public Rectangle(int w, int h)
{
Width = w;
Height = h;
}