Явні перетворення
Існує велике число перетворень, які не можуть бути виконані неявно. При спробі зробити це компілятор видасть помилку. Не можна виконати неявно перетворення:
int в short – можлива втрата даних
int в uint – можлива втрата даних
uint в int – можлива втрата даних
float в int – буде втрачено все, що йде після десяткової крапки
будь-який числовий тип в char – будуть втрачені дані
decimal в будь-який числовий тип – десятковий тип внутрішньо влаштований по-іншому, ніж формати для цілих чисел і чисел з плаваючою комою
Проте ці перетворення можуть бути виконані явно з використанням приведення. Коли один тип приводиться до іншого, компілятор вимушений виконувати перетворення. Типовий синтаксис приведення:
long val = 3.0000;
int I = (int)val; // Допустиме перетворення. Максимум int дорівнює 2147483647.
Тип, до якого необхідно привести значення, указується в круглих дужках перед цим значенням.
Ця операція може бути небезпечною. Ви повинні точно знати, що робите. Навіть просте перетворення з long в int здатне викликати проблему, якщо значення змінної long більше, ніж максимально можливе значення int. Наприклад:
long val = 3000000000;
int I=(int) val; //Неправильное перетворення. Максимальне значення int дорівнює 2147483647.
В даному випадку не видається повідомлення про помилку, але і очікуваний результат не виходить. Якщо ми виконаємо цей код і виведемо на екран величину, яка міститься в I, то отримаємо: -1294967296.
Ніколи не слід покладатися на те, що перетворення типу дасть очікуваний результат. У С# є оператор checked, який можна використовувати для перевірки того, що операція не викликає переповнювання стека. За допомогою цього оператора можна з'ясувати, чи безпечне приведення типу, і змусити середовище виконання згенерувати виключення типу переповнення, якщо це не так:
long val = 3000000000;
int i = checked((int)val);
Пам'ятаючи про те, що будь-яке приведення типів є потенційно небезпечним, у програмі необхідно передбачити код, який оброблятиме можливі помилки приведення типів. Обробку виключень роблять за допомогою конструкції
try ... catch, яка є корисним і необхідним інструментом програміста.
За допомогою приведення типів можна виконувати самі різні перетворення, наприклад:
double price = 25.30;
int approximatePrice = (int)(price + 0.5);
В результаті буде отримана ціна, закруглена до найближчого долара. Проте при такому перетворенні втрачаються дані – все, що йде після десяткової крапки. Це неприпустимо, якщо планується використовувати величину вартості в подальших розрахунках. Проте корисно в тому випадку, якщо необхідно вивести на екран приблизний результат виконаного або частково виконаного розрахунку і ви не хочете лякати користувача великим числом знаків після коми.
Подивимося, що відбувається при перетворенні цілого без знаку в char:
ushort з = 43;
char symbol = (char)з;
Console.WriteLine(symbol);
На екран буде виведений символ, що має ASCII-код 43, тобто знак +. Можна проводити практично будь-які перетворення між числовими типами (включаючи char), якими б безглуздими вони не були, і вони працюватимуть. Наприклад, можна перетворити з decimal в char і навпаки:
decimal d = 65m;
char symbol = (char)d; // В результаті виходить буква А
char з = 'А';
decimal val = (decimal)з;// В результаті виходить число 65
Якщо значення, отримане в результаті приведення, не може поміститися в новий тип даних, перетворення все одно буде виконано, проте результат буде не таким, який очікується. Наприклад:
int I = -1;
char symbol = (char)I;
Це перетворення не повинне працювати, оскільки тип char не може набувати негативних значень. Проте помилки не відбувається, замість цього змінній symbol привоїти значення у вигляді знаку запитання (?).
Перетворення між типами за значенням не обмежується окремими змінними. Наприклад, можна перетворити елемент масиву типу double змінну структури типу int:
struct ItemDetails
{
public string Description;
public int ApproxPrice;
}
Double[] Prices = { 25.30, 26.20, 27.40, 30.00 };