Помимо операций присваивания, преобразование типов происходит и в самих выражениях. В выражении можно свободно смешивать два или более типа данных, при условии их совместимости друг с другом. Например, в одном выражении допускается применение типов short
и long
, поскольку оба типа являются числовыми. Когда в выражении смешиваются разные типы данных, они преобразуются в один и тот же тип по порядку следования операций.
Преобразования типов выполняются по принятым в C# правилам продвижения типов. Ниже приведен алгоритм, определяемый этими правилами для операций с двумя операндами.
ЕСЛИ один операнд имеет тип decimal
, ТО и второй операнд продвигается к типу decimal
(но если второй операнд имеет тип float
или double
, результат будет ошибочным).
ЕСЛИ один операнд имеет тип double
, ТО и второй операнд продвигается к типу double
.
ЕСЛИ один операнд имеет тип float
, ТО и второй операнд продвигается к типу float
.
ЕСЛИ один операнд имеет тип ulong
, ТО и второй операнд продвигается к типу ulong
(но если второй операнд имеет тип sbyte
, short
, int
или long
, результат будет ошибочным).
ЕСЛИ один операнд имеет тип long
, ТО и второй операнд продвигается к типу long
.
ЕСЛИ один операнд имеет тип uint
, а второй — тип sbyte
, short
или int
, ТО оба операнда продвигаются к типу long
.
ЕСЛИ один операнд имеет тип uint
, ТО и второй операнд продвигается к типу uint
.
ИНАЧЕ оба операнда продвигаются к типу int
.
Относительно правил продвижения типов необходимо сделать ряд важных замечаний. Во-первых, не все типы могут смешиваться в выражении. В частности, неявное преобразование типа float
или double
в тип decimal
невозможно, как, впрочем, и смешение типа ulong
с любым целочисленным типом со знаком. Для смешения этих типов требуется явное их приведение.
Во-вторых, особого внимания требует последнее из приведенных выше правил. Оно гласит: если ни одно из предыдущих правил не применяется, то все операнды продвигаются к типу int
. Следовательно, все значения типа char
, sbyte
, byte
, ushort
и short
продвигаются к типу int
в целях вычисления выражения. Такое продвижение типов называется целочисленным. Это также означает, что результат выполнения всех арифметических операций будет иметь тип не ниже int
.
Следует иметь в виду, что правила продвижения типов применяются только к значениям, которыми оперируют при вычислении выражения. Так, если значение переменной типа byte
продвигается к типу int
внутри выражения, то вне выражения эта переменная по-прежнему относится к типу byte
. Продвижение типов затрагивает только вычисление выражения.
Но продвижение типов может иногда привести к неожиданным результатам. Если, например, в арифметической операции используются два значения типа byte
, то происходит следующее. Сначала операнды типа byte
продвигаются к типу int
. А затем выполняется операция, дающая результат типа int
. Следовательно, результат выполнения операции, в которой участвуют два значения типа byte
, будет иметь тип int
. Но ведь это не тот результат, который можно было бы с очевидностью предположить. Рассмотрим следующий пример программы.
// Пример неожиданного результата продвижения типов!
using System;
class PromDemo {
static void Main() {
byte b;
b = 10;
b = (byte)(b * b); // Необходимо приведение типов!!
Console.WriteLine("b: " + b);
}
}
Как ни странно, но когда результат вычисления выражения b*b
присваивается обратно переменной b
, то возникает потребность в приведении к типу byte!
Объясняется это тем, что в выражении b * b
значение переменной b
продвигается к типу int
и поэтому не может быть присвоено переменной типа byte
без приведения типов. Имейте это обстоятельство в виду, если получите неожиданное сообщение об ошибке несовместимости типов в выражениях, которые, на первый взгляд, кажутся совершенно правильными.
Аналогичная ситуация возникает при выполнении операций с символьными операндами. Например, в следующем фрагменте кода требуется обратное приведение к типу char
, поскольку операнды ch1
и сh2
в выражении продвигаются к типу int
.
char ch1 = 'a', ch2 = 'b';
chl = (char)(ch1 + ch2);
Без приведения типов результат сложения операндов ch1
и сh2
будет иметь тип int
, и поэтому его нельзя присвоить переменной типа char
.
Продвижение типов происходит и при выполнении унарных операций, например с унарным минусом. Операнды унарных операций более мелкого типа, чем int
(byte
, sbyte
, short
и ushort
), т.е. с более узким диапазоном представления чисел, продвигаются к типу int
. То же самое происходит и с операндом типа char
. Кроме того, если выполняется унарная операция отрицания значения типа uint
, то результат продвигается к типу long
.
Приведение несовместимых типов | Приведение типов в выражениях |