Г. Шилдт - Полный справочник по C# (1160789), страница 16
Текст из файла (страница 16)
Язык С#ние, хранимое в int-переменной i , преобразуется в значение типа f l o a t , а затемприсваивается переменной f. Но, поскольку в С# не все типы совместимы и действует строгий контроль типов, не все преобразования типов разрешены в неявном виде.Например, типы bool и i n t несовместимы. Тем не менее с помощью операции приведения типов все-таки возможно выполнить преобразование между несовместимымитипами. Приведение типов — это выполнение преобразования типов в явном виде.Автоматическое преобразование типовПри присвоении значения одного типа данных переменной другого типа будет выполнено автоматическое преобразование типов, если• эти два типа совместимы;• тип приемника больше (т.е. имеет больший диапазон представления чисел),чем тип источника.При соблюдении этих двух условий выполняется преобразование с расширением, илирасширяющее преобразование. Например, тип i n t — достаточно "большой" тип, чтобысохранить любое допустимое значение типа byte, а поскольку как i n t , так и b y t e —целочисленные типы, здесь может быть применено автоматические преобразование.Для расширяющих преобразований числовые типы, включая целочисленные и сплавающей точкой, совместимы один с другим.
Например, следующая программа совершенно легальна, поскольку преобразование типов из long в double является расширяющим, которое выполняется автоматически.// Демонстрация автоматического преобразования типов// из long в double.using System;class LtoD {public static void Main() {long redouble D;L = 100123285L;D = L;Console.WriteLine("L и D: " + L + " " + D ) ;Несмотря на возможность автоматического преобразования типов из long вdouble, обратное преобразование типов (из double в long) автоматически не выполняется, поскольку это преобразование не является расширяющим.
Таким образом,следующая версия предыдущей программы недопустима:// *** Эта программа не будет скомпилирована. ***using System;class LtoD {public static void Main() {long L;double D;D = 100123285.0;L = D; // Неверно!!!Глава З. Типы данных, литералы и переменные73Console.WriteLine("L и D: " + L + " " + D ) ;Помимо только что описанных ограничений не существует автоматического преобразования между типом decimal и f l o a t (или double), а также из числовых типовв тип char (или bool). Кроме того, несовместимы и типы char и bool .Приведение несовместимых типовНесмотря на большую пользу автоматического преобразования типов оно не в состоянии удовлетворить все нужды программирования, поскольку реализуется толькопри расширяющем преобразовании между совместимыми типами. Во всех остальныхслучаях приходится применять приведение к типу.
Приведение к типу — это явно заданная инструкция компилятору преобразовать один тип в другой. Инструкция приведения записывается в следующей общей форме:(тип_приемника) выражениеЗдесь элемент тип_приемника определяет тип для преобразования заданного выражения. Например, если вам нужно, чтобы выражение х/у имело тип i n t , напишитеследующие программные инструкции:Idouble х, у;// . .
.(int) (х / у) ;В этом фрагменте кода, несмотря на то, что переменные х и у имеют тип double,результат вычисления заданного выражения приводится к типу i n t . Круглые скобки,в которые заключено выражение х / у , обязательны. В противном случае (без круглыхскобок) операция приведения к типу i n t была бы применена только к значению переменной х, а не к результату деления. Для получения результата желаемого типаздесь не обойтись без операции приведения, поскольку автоматического преобразования из типа double в i n t не существует.Если приведение приводит к сужающему преобразованию, возможна потеря информации. Например, в случае приведения типа long к типу i n t информация будет утеряна, если значение типа long больше максимально возможного числа, которое способен представить тип i n t , поскольку будут "усечены" старшие разряды longзначения.
При выполнении операции приведения типа с плавающей точкой к целочисленному будет утеряна дробная часть простым ее отбрасыванием. Например, приприсвоении переменной целочисленного типа числа 1,23 в действительности будетприсвоено число 1. Дробная часть (0,23) будет утеряна.В следующей программе демонстрируется ряд преобразований типов, которые требуют приведения типов, причем в некоторых ситуациях приведение вызывает потерюданных.// Демонстрация приведения типов.using System;class CastDemo {public s t a t i c void Main() {double x, y;byte b;int i ;char ch;uint u;74Часть I. Язык С#short s;long 1;x = 10.0;У = 3.0;// Приведение типа double к типу int.i = (int) (x / y ) ; // Дробная часть теряется.Console.WriteLine("Целочисленный результат деления х / у: " + i ) ;Console.WriteLine();// Приведение типа int к типу byte без потери данных.i = 255;b = (byte) i;Console.WriteLine("b после присваивания 255: " + b +1111— без потери данных.
);// Приведение типа int к типу byte с потерей данныхi = 257;b = (byte) i;Console.WriteLine("b после присваивания 257: " + b +11— с потерей данных.");Console.WriteLine();// Приведение типа uint к типу short без потери данных,и = 32000;s = (short) u;Console.WriteLine("s после присваивания 32000: " + s +" — без потери данных.");// Приведение типа uint к типу short с потерей данных.и = 64000;s = (short) u;Console.WriteLine("s после присваивания 64 000: " + s +" -- с потерей данных.");Console.WriteLine();// Приведение типа long к типу uint без потери данных.1 = 64000;u = (uint) 1;Console.WriteLine("u после присваивания 64000: " + и +" -- без потери данных.");// Приведение типа long к типу uint с потерей данных.1 - -12;u = (uint) 1;Console.WriteLine("u после присваивания -12: " + и +" -- с потерей данных.");Console.WriteLine();// Приведение типа byte к типу char.b = 88; // ASCII-код для буквы X.ch = (char) b;Console.WriteLine("ch после присваивания 88: " + ch);Глава З.
Типы данных, литералы и переменные75Результаты выполнения этой демонстрационной программы имеют такой вид:Целочисленный результат деления х / у: 3b после присваивания 255: 255 — без потери данных,b после присваивания 257: 1 -- с потерей данных.s после присваивания 32000: 32000 —s после присваивания 64000: -1536 —без потери данных,с потерей данных.и после присваивания 64000: 64000 -- без потери данных,и после присваивания -12: 4294967284 -- с потерей данных.ch после присваивания 88: XТеперь рассмотрим каждую инструкцию присваивания отдельно. Приведение результата деления (х / у) к типу i n t приводит к усечению дробной части, т.е.
к потереинформации.Однако никакой потери информации не происходит, если переменной b присваивается значение 255, поскольку переменная типа b y t e в состоянии хранить число 255.Но при попытке присвоить переменной b число 257 информация будет потеряна, поскольку число 257 находится за пределами диапазона представления чисел для типаbyte. В обоих этих случаях без операции приведения типов не обойтись, посколькуавтоматическое преобразование типа i n t в тип b y t e невозможно.В случае присвоения переменной s типа s h o r t значения 32 000 (с помощью переменной и типа u i n t ) данные не теряются, потому что short-переменная может хранить число 32 000.
Но следующее присвоение уже не такое успешное, поскольку число 64 000 находится за пределами диапазона представления чисел для типа s h o r t , иэта ситуация сопровождается потерей данных. В обоих этих случаях без операцииприведения типов также не обойтись, поскольку автоматическое преобразование типаu i n t в тип s h o r t невозможно.Затем в программе переменной и (типа u i n t ) присваивалось значение 64 000(с помощью переменной 1 типа long). Эта инструкция была выполнена без потериданных, поскольку число 64 000 находится в пределах u int-диапазона. Но попыткаприсвоить той же переменной и число —12, конечно, привела к потере данных, таккак тип u i n t не предназначен для хранения отрицательных чисел. И в этих обоихслучаях без операции приведения типов не обойтись, поскольку автоматическое преобразование типа long в тип u i n t невозможно.Наконец, присваивание byte-значения переменной типу char обходится "безжертв", т.е.
без потери информации, но здесь также необходимо применять операциюприведения типов.I Преобразование типов в выраженияхПреобразование типов встречается не только в инструкциях присваивания, но и ввыражениях. В выражениях можно смешивать различные типы данных, если они совместимы. Например, можно смешивать типы s h o r t и long, поскольку это числовыетипы. При смешении различных типов в одном выражении все его составляющиепреобразуются к одному типу, причем это происходит по мере перехода от одной операции к другой.Преобразование типов выполняется на основе правил продвижения по "типовой"лестнице.
Для бинарных операций действует следующий алгоритм.76Часть I. Язык С#ЕСЛИ один операнд имеет тип decimal, TO и второй "возводится в ранг", т.е. "втип" decimal (но если второй операнд имеет тип f l o a t или double, результат будет ошибочным).ЕСЛИ один операнд имеет тип double, TO и второй преобразуется в значение типа double.ЕСЛИ один операнд имеет тип f l o a t , TO и второй преобразуется в значение типаfloat.ЕСЛИ один операнд имеет тип ulong, TO и второй преобразуется в значение типаulong (но если второй операнд имеет тип sbyte, s h o r t , i n t или long, результатбудет ошибочным).ЕСЛИ один операнд имеет тип long, TO и второй преобразуется в значение типаlong.ЕСЛИ один операнд имеет тип u i n t , а второй имеет тип sbyte, s h o r t или i n t ,ТО оба операнда преобразуются в значения типа long.ЕСЛИ один операнд имеет тип u i n t , TO и второй преобразуется в значение типаuint.ИНАЧЕ оба операнда преобразуются в значения типа i n t .Относительно правил продвижения по "типовой" лестнице необходимо сделатьнесколько замечаний.