Страница 17 из 188
// Продемонстрировать неявное преобразование типа long в тип double.using System;
class LtoD { static void Main() { long L; double D; L = 100123285L; D = L; Console.WriteLine("L и D: " + L + " " + D); }}Если тип long может быть преобразован в тип double неявно, то обратное преобразование типа double в тип long неявным образом невозможно, поскольку ононе является расширяющим. Следовательно, приведенный ниже вариант предыдущейпрограммы составлен неправильно.
// Эта программа не может быть скомпилирована. using System;class LtoD { static void Main() { long L; double D; D = 100123285.0; L = D; // Недопустимо!!! Console.WriteLine("L и D: " + L + " " + D); }}Помимо упомянутых выше ограничений, не допускается неявное взаимное преобразование типов decimal и float иди double, а также числовых типов и char илиbool. Кроме того, типы char и bool несовместимы друг с другом.### Приведение несовместимых типовНесмотря на всю полезность неявных преобразований типов, они неспособны удовлетворить все потребности в программировании, поскольку допускают лишь расширяющие преобразования совместимых типов. А во всех остальных случаях приходитсяобращаться к приведению типов. Приведение — это команда компилятору преобразовать результат вычисления выражения в указанный тип. А для этого требуется явноепреобразование типов. Ниже приведена общая форма приведения типов.
(целевой_тип) выражениеЗдесь целевой_тип обозначает тот тип, в который желательно преобразовать указанное выражение. Рассмотрим для примера следующее объявление переменных.
double х, у;Если результат вычисления выражения х/у должен быть типа int, то следует записать следующее.
(int) (х / у)Несмотря на то что переменные х и у относятся к типу double, результат вычисления выражения х/у преобразуется в тип int благодаря приведению. В данном примере выражение х/у следует непременно указывать в скобках, иначе приведение к типуint будет распространяться только на переменную х, а не на результат ее деления напеременную у. Приведение типов в данном случае требуется потому, что неявное преобразование типа double в тип int невозможно.Если приведение типов приводит к сужающему преобразованию, то часть информации может быть потеряна. Например, в результате приведения типа long к типу intчасть информации потеряется, если значение типа long окажется больше диапазонапредставления чисел для типа int, поскольку старшие разряды этого числового значения отбрасываются. Когда же значение с плавающей точкой приводится к целочисленному, то в результате усечения теряется дробная часть этого числового значения. Так,если присвоить значение 1,23 целочисленной переменной, то в результате в ней останется лишь целая часть исходного числа (1), а дробная его часть (0,23) будет потеряна.В следующем примере программы демонстрируется ряд преобразований типов,требующих приведения. В этом примере показан также ряд ситуаций, в которых приведение типов становится причиной потери данных.
// Продемонстрировать приведение типов.using System;
class CastDemo { static void Main() { double x, y; byte b; int i; char ch; uint u; short s; long 1; x = 10.0; у = 3.0; // Приведение типа double к типу int, дробная часть числа теряется. i = (int) (х / у); Console.WriteLine("Целочисленный результат деления х / у: " + i); Console.WriteLine(); // Приведение типа int к типу byte без потери данных, i = 255; b = (byte) i; Console.WriteLine("b после присваивания 255: " + b + " -- без потери данных."); // Приведение типа int к типу byte с потерей данных, i = 257; b = (byte) i; Console.WriteLine("b после присваивания 257: " + b + " -- с потерей данных."); Console.WriteLine(); // Приведение типа uint к типу short без потери данных. u = 32000; s = (short) u; Console.WriteLine("s после присваивания 32000: " + s + " -- без потери данных."); // Приведение типа uint к типу short с потерей данных, u = 64000; s = (short) u; Console.WriteLine("s после присваивания 64000: " + s + " -- с потерей данных."); Console.WriteLine(); // Приведение типа long к типу uint без потери данных. l = 64000; u = (uint) l; Console.WriteLine ("u после присваивания 64000: " + u + " -- без потери данных."); // Приведение типа long к типу uint с потерей данных. l = -12; u = (uint) l; Console.WriteLine("и после присваивания -12: " + u + " -- с потерей данных."); Console.WriteLine(); // Приведение типа int к типу char, b = 88; // код ASCII символа X ch = (char) b; Console.WriteLine("ch после присваивания 88: " + ch);}
}Вот какой результат дает выполнение этой программы.Целочисленный результат деления х / у: 3b после присваивания 255: 255 -- без потери данных.b после присваивания 257: 1 -- с потерей данных.s после присваивания 32000: 32000 -- без потери данных.s после присваивания 64000: -1536 -- с потерей данных.u после присваивания 64000: 64000 -- без потери данных.u после присваивания -12: 4294967284 -- с потерей данных.ch после присваивания 88: X
Рассмотрим каждую операцию присваивания в представленном выше примерепрограммы по отдельности. Вследствие приведения результата деления х/у к типуint отбрасывается дробная часть числа, а следовательно, теряется часть информации.
Когда переменной b присваивается значение 255, то информация не теряется, поскольку это значение входит в диапазон представления чисел для типа byte. Но когдапеременной b присваивается значение 257, то часть информации теряется, посколькуэто значение превышает диапазон представления чисел для типа byte. Приведениетипов требуется в обоих случаях, поскольку неявное преобразование типа int в типbyte невозможно.
Когда переменной s типа short присваивается значение 32 000 переменной и типаuint, потери данных не происходит, поскольку это значение входит в диапазон представления чисел для типа short. Но в следующей операции присваивания переменная и имеет значение 64 000, которое оказывается вне диапазона представления чиселдля типа short, и поэтому данные теряются. Приведение типов требуется в обоихслучаях, поскольку неявное преобразование типа uint в тип short невозможно.
Далее переменной u присваивается значение 64 000 переменной l типа long.В этом случае данные не теряются, поскольку значение 64 000 оказывается вне диапазона представления чисел для типа uint. Но когда переменной u присваивается значение -12, данные теряются, поскольку отрицательные числа также оказываются внедиапазона представления чисел для типа uint. Приведение типов требуется в обоихслучаях, так как неявное преобразование типа long в тип uint невозможно.
И наконец, когда переменной char присваивается значение типа byte, информация не теряется, но приведение типов все же требуется.Преобразование типов в выражениях
Помимо операций присваивания, преобразование типов происходит и в самих выражениях. В выражении можно свободно смешивать два или более типа данных, приусловии их совместимости друг с другом. Например, в одном выражении допускается применение типов short и long, поскольку оба типа являются числовыми. Когдав выражении смешиваются разные типы данных, они преобразуются в один и тот жетип по порядку следования операций.
Преобразования типов выполняются по принятым в C# правилам продвижения типов. Ниже приведен алгоритм, определяемый этими правилами для операций с двумяоперандами.
ЕСЛИ один операнд имеет тип decimal, ТО и второй операнд продвигается к типу decimal (но если второй операнд имеет тип float или double, результат будет ошибочным).
ЕСЛИ один операнд имеет тип double, ТО и второй операнд продвигается к типу double.
ЕСЛИ один операнд имеет тип float, ТО и второй операнд продвигается к типу float.
ЕСЛИ один операнд имеет тип ulong, ТО и второй операнд продвигается к типу ulong (но если второй операнд имеет тип sbyte, short, int или long, результат будет ошибочным).