- •Тема 6. Основы программирования на языке c#
- •Условная операция
- •Операции checked и unchecked
- •Операция поглощения null
- •Безопасность типов
- •Преобразования типов
- •Неявные преобразования
- •Явные преобразования
- •Проверка равенства объектов
- •Упаковка и распаковка
- •Виртуальный метод Equals()
- •Статический метод Equals()
- •Проверка типов значений на равенство
- •Перегрузка операций
- •Как работают операции
- •Пример перегрузки операции: структура Vector
- •Добавление дополнительных перегрузок
- •Перегрузка операций сравнения
- •Пользовательские приведения
- •Реализация пользовательских приведений
- •Приведение между классами
- •Приведение между базовым и производным классами
- •Упаковывающие и распаковывающие приведения
- •Множественные приведения
Преобразования типов
Часто возникает необходимость в преобразовании данных из одного типа в другой. Рассмотрим следующий код:
byte value1 = 10;
byte value2 = 23;
byte total;
total = valuel + value2;
Console.WriteLine(total);
Если вы попытаетесь скомпилировать эти строки, то получите сообщение об ошибке:
Cannot implicitly convert type ’int' to 'byte'
Неявное преобразование типа 'int' в ’byte' невозможно
Проблема здесь в том, что если складывать два байта, результат будет возвращен как int, а не другой byte. Это потому, что byte может содержать только восемь бит данных, поэтому сложение двух байт очень легко может дать результат, который не уместится в один тип byte. Если результат необходимо сохранить в переменной типа byte, его потребуется преобразовать в byte. Последующие разделы посвящены двум механизмам такого преобразования, поддерживаемым в C# явному (explicit) и неявному (implicit) преобразованию.
Неявные преобразования
Преобразования типов обычно могут быть выполнены автоматически (неявно) только в том случае, когда при этом можно гарантировать, что значение не будет изменено никоим образом. Именно по этой причине не работает предыдущий пример; пытаясь преобразовать int в byte, потенциально можно потерять 3 байта данных. Компилятор не позволит это сделать, если только явно не сообщить ему о том, что именно это и требуется. Однако если поместить результат в переменную long вместо byte, то проблем не будет:
byte valuel = 10;
byte value2 = 23;
long total; // это скомпилируется нормально
total = valuel + value2;
Console.WriteLine(total);
Этот код скомпилируется без ошибок, поскольку long содержит больше байт, чем byte, так что нет риска утери данных. В таких случаях компилятор спокойно осуществляет требуемые преобразования, и его не нужно просить об этом явно.
В табл. 7.5 показаны неявные преобразования типов, поддерживаемые С#.
Таблица 7.5. Неявные пребразования типов, поддерживаемые в C#
Из |
В |
sbyte |
short, int, long, float, double, decimal, BigInteger |
byte |
short, ushort, int, uint, long, ulong, float, double, decimal, BigInteger |
short |
int, long, float, double, decimal, BigInteger |
ushort |
int, uint, long, ulong, double, decimal, BigInteger |
int |
long, float, double, decimal, BigInteger |
uint |
long, ulong, float, double, decimal, BigInteger |
long, ulong |
double, decimal, BigInteger |
float |
double, BigInteger |
char |
ushort, int, uint, long, ulong, floar, double, decimal, BigInteger |
Как и следовало ожидать, неявные преобразования допускаются только от меньших целых типов к большим, но не наоборот. Можно также преобразовывать данные между целыми и действительными значениями, однако здесь правила слегка отличаются. Допускается преобразовывать данные между типами одинакового размера, например, из int/uint в float и long/ulong в double, однако можно также выполнять преобразование long/ulong в float. При этом может быть потеряно 4 байта, но это означает только, что полученное значение float будет менее точным, чем double; компилятор не трактует это как ошибку, потому что модуль значения не изменяется. Можно также присваивать значение переменной типа без знака переменной типа со знаком, если значение первой окажется в пределах допустимых значений второй.
Относительно преобразования типов, допускающих null-значения, приняты описанные ниже дополнительные соглашения.
Допускающие null типы неявно преобразуются в другие типы, допускающие null, подчиняясь правилам, описанным в табл. 7.5; т.е. int? неявно преобразуется в long?, float?, double? и decimal?.
Не допускающие null типы неявно преобразуются в типы, допускающие null, согласно тем же правилам. То есть int неявно преобразуется в long, float, double и decimal.
Допускающие null типы не могут быть неявно преобразованы в типы, не допускающие null; для этого должно выполняться явное преобразование, как описано в следующем разделе. Дело в том, что переменные этих типов могут содержать значение null, которое невозможно представить типом, не допускающим null.
