Книга: C# 4.0: полное руководство
Преобразование и приведение типов
Преобразование и приведение типов
В программировании нередко значения переменных одного типа присваиваются переменным другого типа. Например, в приведенном ниже фрагменте кода целое значение типа int присваивается переменной с плавающей точкой типа float.
int i; float f;
i = 10;
f = i; // присвоить целое значение переменной типа float
Если в одной операции присваивания смешиваются совместимые типы данных, то значение в правой части оператора присваивания автоматически преобразуется в тип, указанный в левой его части. Поэтому в приведенном выше фрагменте кода значение переменной i сначала преобразуется в тип float, а затем присваивается переменной f. Но вследствие строгого контроля типов далеко не все типы данных в C# оказываются полностью совместимыми, а следовательно, не все преобразования типов разрешены в неявном виде. Например, типы bool и int несовместимы. Правда, преобразование несовместимых типов все-таки может быть осуществлено путем приведения. Приведение типов, по существу, означает явное их преобразование. В этом разделе рассматривается как автоматическое преобразование, так и приведение типов.
Автоматическое преобразование типов
Когда данные одного типа присваиваются переменной другого типа, неявное преобразование типов происходит автоматически при следующих условиях:
• оба типа совместимы;
• диапазон представления чисел целевого типа шире, чем у исходного типа.
Если оба эти условия удовлетворяются, то происходит расширяющее преобразование. Например, тип int достаточно крупный, чтобы вмещать в себя все действительные значения типа byte, а кроме того, оба типа, int и byte, являются совместимыми целочисленными типами, и поэтому для них вполне возможно неявное преобразование.
Числовые типы, как целочисленные, так и с плавающей точкой, вполне совместимы друг с другом для выполнения расширяющих преобразований. Так, приведенная ниже программа составлена совершенно правильно, поскольку преобразование типа long в тип double является расширяющим и выполняется автоматически.
// Продемонстрировать неявное преобразование типа 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 l;
x = 10.0;
y = 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 + " -- без потери данных.");
// Приведение типа 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("и после присваивания 64000: " + u + " -- без потери данных.");
// Приведение типа long к типу uint с потерей данных.
l = -12;
u = (uint)1;
Console.WriteLine("и после присваивания -12: " + u + " — с потерей данных.");
Console.WriteLine();
// Приведение типа int к типу char,
b = 88; // код ASCII символа X
ch = (char) b;
Console.WriteLine("ch после присваивания 88: " + ch);
}
}
Вот какой результат дает выполнение этой программы.
Целочисленный результат деления х / у: 3
b после присваивания 255: 255 -- без потери данных.
b после присваивания 257: 1 — с потерей данных.i
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 невозможно.
Далее переменной и присваивается значение 64 000 переменной 1 типа long. В этом случае данные не теряются, поскольку значение 64 000 оказывается вне диапазона представления чисел для типа uint. Но когда переменной и присваивается значение -12, данные теряются, поскольку отрицательные числа также оказываются вне диапазона представления чисел для типа uint. Приведение типов требуется в обоих случаях, так как неявное преобразование типа long в тип uint невозможно.
И наконец, когда переменной char присваивается значение типа byte, информация не теряется, но приведение типов все же требуется.
- О значении типов данных
- Типы значений в C#
- Целочисленные типы
- Типы для представления чисел с плавающей точкой
- Десятичный тип данных
- Символы
- Логический тип данных
- Некоторые возможности вывода
- Литералы
- Более подробное рассмотрение переменных
- Область действия и время существования переменных
- Преобразование и приведение типов
- Преобразование типов в выражениях
- 7. Лекция: Преобразование типов
- Приведение и преобразование типов
- Преобразование типов в выражениях
- 2.2. Приведение типов
- Приведение числовых типов
- Преобразование XML в реляционную базу данных
- Преобразование строки в целое: stoi( )
- Использование типов содержимого и столбцов
- 5.3 Классификация типов резервного копирования
- 2.7 Преобразования типов
- Описание типов модулей оперативной памяти
- Объекты без прототипов