1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 16
Текст из файла (страница 16)
В обоих этих случаях без операции приведениятипов также не обойтись, поскольку автоматическое преобразование типа uint в типshort невозможно.Затем в программе переменной u (типа uint) присваивалось значение 64 000 (спомощью переменной l типа long). Эта инструкция была выполнена без потери данных,поскольку число 64 000 находится в пределах uint-диапазона. Но попытка присвоить тойже переменной u число -12, конечно, привела к потере данных, так как тип uint непредназначен для хранения отрицательных чисел.
И в этих обоих случаях без операцииприведения типов не обойтись, поскольку автоматическое преобразование типа long в типuint невозможно.Наконец, присваивание byte-значения переменной типу char обходится “безжертв”, т.е. без потери информации, но здесь также необходимо применять операциюприведения типов.Преобразование типов в выраженияхПреобразование типов встречается не только в инструкциях присваивания, но и ввыражениях. В выражениях можно смешивать различные типы данных, если онисовместимы.
Например, можно смешивать типы short и long, поскольку это числовыетипы. При смешении различных типов в одном выражении все его составляющиепреобразуются к одному типу, причем это происходит по мере перехода от одной операциик другой.Преобразование типов выполняется на основе правил продвижения по “типовой”лестнице.
Для бинарных операций действует следующий алгоритм.76Часть I. Язык C#ЕСЛИ один операнд имеет тип decimal, TO и второй “возводится в ранг”, т.е. “втип” decimal (но если второй операнд имеет тип float или double, результат будетошибочным).ЕСЛИ один операнд имеет тип double, TO и второй преобразуется в значение типаdouble.ЕСЛИ один операнд имеет тип float, TO и второй преобразуется в значение типаfloat.ЕСЛИ один операнд имеет тип ulong, TO и второй преобразуется в значение типаulong (но если второй операнд имеет тип sbyte, short, int или long, результат будетошибочным).ЕСЛИ один операнд имеет тип long, TO и второй преобразуется в значение типаlong.ЕСЛИ один операнд имеет тип uint, а второй имеет тип sbyte, short или int, ТОоба операнда преобразуются в значения типа long.ЕСЛИ один операнд имеет тип uint, TO и второй преобразуется в значение типаuint.ИНАЧЕ оба операнда преобразуются в значения типа int.Относительно правил продвижения по “типовой” лестнице необходимо сделатьнесколько замечаний.
Во-первых не все типы можно смешивать в одном выражении.Например, не выполняется неявное преобразование значения типа float или double взначение типа decimal. Нельзя также смешивать тип ulong и целочисленный тип сознаком. Чтобы все-таки объединить эти несовместимые типы в одном выражении,необходимо использовать в явном виде операцию приведения типов.Во-вторых, уделите особое внимание последнему правилу. Оно утверждает, что всеоперанды будут преобразованы в значения типа int, если не было применено ни одно ихпредыдущих правил.
Следовательно, в выражении все char-, sbyte-, byte-, ushort- иshort-значения будут в процессе вычислений преобразованы в значения типа int. Такое“поголовное” int-преобразование называют целочисленным продвижением типа (integerpromotion). Следствием этого алгоритма является то, что результат всех арифметическихопераций будет иметь тип по “званию” не ниже int.Важно понимать, что продвижение типов применяется только к значениям,используемым при вычислении выражения. Например, хотя значение переменной типаbyte внутри выражения будет “подтянуто” до типа int, вне выражения эта переменнаяпо-прежнему имеет тип byte. Правило продвижения типов действует только привычислении выражения.Однако продвижение типов может иметь неожиданные последствия. Например,предположим, что арифметическая операция включает два byte-значения.
Тогдавыполняется следующая последовательность действий. Сначала byte-операнды“подтягиваются” до типа int, затем вычисляется результат операции, который имеет типint. Выходит, после выполнения операции над двумя byte-операндами вместоожидаемого byte-результата мы получим int-значение. Именно такая неожиданность иможет иметь место. А теперь рассмотрим такую программу:// Сюрприз в результате продвижения типов!using System;class PromDemo {public static void Main() {byte b;Глава 3. Типы данных, литералы и переменные77b = 10;b = (byte) (b * b); // Необходимо приведение типов)!!}}Console.WriteLine("b: "+ b);Кажется странным, что при присвоении результата произведения b * b переменнойb необходимо выполнять операцию приведения типов. Дело в том, что в выражении b * bзначение переменной b “подтягивается” до типа int, т.е.
результат выражения b * bпредставляет собой int-значение, которое нельзя присвоить byte-переменной безприведения типов. Имейте это в виду, если вдруг получите сообщение об ошибке, гдесказано о несовместимости типов для выражений, в которых, казалось бы, все в полномпорядке.Ситуация подобного рода встречается также при выполнении операций надоперандами типа char. Например, в следующем фрагменте кода также необходимо“возвратить” результат к исходному типу из-за автоматического преобразования charоперандов к типу int внутри вычисляемого выражения.char ch1 = 'a', ch2 = 'b';ch1 = (char) (ch1 + ch2);Без приведения типов результат сложения операндов ch1 и ch2 имел бы тип int, аint-значение невозможно присвоить char-переменной.Продвижение типов также имеет место при выполнении унарных операций(например, с унарным минусом).
Операнды унарных операций, тип которых по диапазонуменьше типа int (т.е. sbyte-, byte-, short- и ushort-значения), “подтягиваются” ктипу int. To же происходит с операндом типа char. Более того, при выполнении операцииотрицания uint-значения результат приобретает тип long.Приведение типов в выраженияхОперацию приведения типов можно применить не ко всему выражению, а кконкретной его части. Это позволяет более тонко управлять преобразованием типов привычислении выражения. Рассмотрим, например, следующую программу.
Она отображаетзначения квадратных корней из чисел от 1 до 10. Она также выводит по отдельности целуюи дробную части каждого результата. Для этого в программе используется операцияприведения типов, которая позволяет преобразовать результат вызова методаMath.Sqrt() в значение типа int.// Приведение типов в выражениях.using System;class CastExpr {public static void Main() {double n;for(n = 1.0; n <= 10; n++) {Console.WriteLine("Квадратный корень из {0} равен {1}",n, Math.Sqrt(n));Console.WriteLine("Целая часть числа: {0}" ,(int) Math.Sqrt(n));Console.WriteLine(78Часть I.
Язык C#"Дробная часть числа: {0}",Math.Sqrt(n) - (int) Math.Sqrt(n) );}}Console.WriteLine();}Вот как выглядят результаты выполнения этой программы:Квадратный корень из 1 равен 1Целая часть числа: 1Дробная часть числа: 0Квадратный корень из 2 равен 1,4142135623731Целая часть числа: 1Дробная часть числа: 0,414213562373095Квадратный корень из 3 равен 1,73205080756888Целая часть числа: 1Дробная часть числа: 0,732050807568877Квадратный корень из 4 равен 2Целая часть числа: 2Дробная часть числа: 0Квадратный корень из 5 равен 2,23606797749979Целая часть числа: 2Дробная часть числа: 0,23606797749979Квадратный корень из 6 равен 2,44948974278318Целая часть числа: 2Дробная часть числа: 0,449489742783178Квадратный корень из 7 равен 2,64575131106459Целая часть числа: 2Дробная часть числа: 0,645751311064591Квадратный корень из 8 равен 2,82842712474619Целая часть числа: 2Дробная часть числа: 0,82842712474619Квадратный корень из 9 равен 3Целая часть числа: 3Дробная часть числа: 0Квадратный корень из 10 равен 3,16227766016938Целая часть числа: 3Дробная часть числа: 0,16227766016838Как видно из результатов выполнения программы, приведение значения,возвращаемого методом Math.Sqrt(), к типу int, позволяет получить целую частьзначения.
А его дробную часть мы получаем в результате вычисления следующеговыражения (если из вещественного числа вычесть его целую часть, то результат дастдробную часть исходного числа):Math.Sqrt(n) - (int) Math.Sqrt(n)Результат этого выражения имеет тип double. Здесь к типу int приводится толькорезультат второго вызова метода Math.Sqrt().Глава 3. Типы данных, литералы и переменные79Полныйсправочник поГлава 4ОператорыВC# предусмотрен широкий набор операторов, которые дают в руки программистумощные рычаги управления при создании разнообразнейших выражений и ихвычислении. В C# имеется четыре общих класса операторов: арифметические, поразрядные,логические и операторы отношений. Помимо них в этой главе рассматриваются операторприсвоения и оператор ?.