Керівництво c #, перетворення типів

У програмуванні нерідко значення змінних одного типу присвоюються змінним іншого типу. Наприклад, у наведеному нижче фрагменті коду ціле значення типу int присвоюється змінної з плаваючою точкою типу float:

Якщо в одній операції присвоювання змішуються сумісні типи даних, то значення в правій частині оператора присвоювання автоматично перетворюється в тип, вказаний в лівій його частині. Тому в наведеному вище фрагменті коду значення змінної i спочатку перетвориться в тип float, а потім присвоюється змінної f. Але внаслідок суворого контролю типів далеко не всі типи даних в C # виявляються повністю сумісними, а отже, не всі перетворення типів дозволені в неявному вигляді. Наприклад, типи bool і int несумісні. Правда, перетворення несумісних типів все-таки може бути здійснено шляхом приведення. Приведення типів, по суті, означає явне їх перетворення.

Автоматичне перетворення типів

Коли дані одного типу присвоюються змінної іншого типу, неявне перетворення типів відбувається автоматично при наступних умовах:

  • обидва типи сумісні
  • діапазон представлення чисел цільового типу ширше, ніж у вихідного типу

Якщо обидва ці умови задовольняються, то відбувається розширює перетворення. Наприклад, тип int досить великий, щоб вміщати в себе всі дійсні значення типу byte, а крім того, обидва типи, int і byte, є сумісними цілочисельними типами, і тому для них цілком можливо неявне перетворення.

Числові типи, як цілочисельні, так і з плаваючою точкою, цілком сумісні один з одним для виконання розширюють перетворень. Розглянемо приклад:

Зверніть увагу на те, що метод Sum () очікує надходження двох параметрів типу int. Проте, в методі Main () йому насправді передаються дві змінних типу short. Хоча це може здатися невідповідністю типів, програма компілюватиметься і виконуватися без помилок і повертати в результаті, як і очікувалося, значення 25.

Причина, по якій компілятор буде вважати даний код синтаксично коректним, пов'язана з тим, що втрата даних тут неможлива. Оскільки максимальне значення (32767), яке може містити тип short, цілком вписується в рамки діапазону типу int (максимальне значення якого становить 2147483647), компілятор буде неявним чином розширювати кожну змінну типу short до типу int. Формально термін "розширення" застосовується для позначення неявного висхідного приведення (upward cast), яке не призводить до втрати даних.

Приведення несумісних типів

Незважаючи на всю корисність неявних перетворень типів, вони нездатні задовольнити всі потреби в програмуванні, оскільки допускають лише розширюють перетворення сумісних типів. А у всіх інших випадках доводиться звертатися до приведення типів. Приведення - це команда компілятору перетворити результат обчислення виразу в зазначений тип. А для цього потрібно явне перетворення типів. Нижче наведена загальна форма приведення типів:

Тут целевой_тіп позначає той тип, в який бажано перетворити вказане вираз.

Якщо приведення типів призводить до звужуючого перетворенню. то частина інформації може бути втрачена. Наприклад, в результаті приведення типу long до типу int частина інформації загубиться, якщо значення типу long виявиться більше діапазону представлення чисел для типу int, оскільки старші розряди цього числового значення відкидаються. Коли ж значення з плаваючою точкою приводиться до целочисленному, то в результаті усічення втрачається дрібна частина цього числового значення. Так, якщо привласнити значення 1,23 цілочисельний змінної, то в результаті в ній залишиться лише ціла частина вихідного числа (1), а дробова його частина (0,23) буде втрачена. Давайте розглянемо приклад:

Результатом роботи даної програми буде:

Зверніть увагу, що змінна i1 коректно перетворилася в тип short, тому що її значення входить в діапазон цього типу даних. Перетворення змінної dec в тип int повернуло цілу частину цього числа. Перетворення змінної i2 повернуло значення переповнення 18964 (тобто 84500 - 2 * 32768).

Перехоплення звужують перетворень даних

У попередньому прикладі приведення змінної i2 до типу short не є прийнятним, тому що виникає втрата даних. Для створення додатків, в яких втрата даних повинна бути неприпустимою, в C # пропонуються такі ключові слова, як checked і unchecked. які дозволяють гарантувати, що втрата даних не виявиться непоміченою.

За замовчуванням, в разі, коли не робиться ніяких відповідних виправних заходів, умови переповнення (overflow) і втрати значущості (underflow) відбуваються без видачі помилки. Обробляти умови переповнення і втрати значущості в додатку можна двома способами. Це можна робити вручну, покладаючись на свої знання і навички в області програмування.

Недолік такого підходу в тому, що навіть в разі застосування максимальних зусиль людина все одно залишається людиною, і якісь помилки можуть вислизнути від його очей.

На щастя, в C # передбачено ключове слово checked. Якщо оператор (або блок операторів) укладено в контекст checked, компілятор C # генерує додаткові CIL-інструкції, що забезпечують перевірку на предмет умов переповнення, які можуть виникати в результаті складання, множення, віднімання або ділення двох числових типів даних.

У разі виникнення умови переповнення під час виконання буде генеруватися виняток System.OverflowException. Давайте розглянемо приклад, в якому будемо передавати в консоль значення виключення:

Результат роботи даної програми:

Керівництво c #, перетворення типів

Налаштування перевірки на предмет виникнення умов переповнення в масштабах проекту

Якщо створюється додаток, в якому переповнення ніколи не повинно проходити непомітно, може з'ясуватися, що обрамляти ключовим словом checked доводиться дратівливо багато рядків коду. На такий випадок в якості альтернативного варіанту в компіляторі C # підтримується прапор / checked. При активізації цього прапора перевірки на предмет можливого переповнення будуть автоматично піддаватися всі наявні в коді арифметичні операції, без застосування для кожної з них ключового слова checked. Виявлення переповнення точно так же призводить до генерації відповідного виключення під час виконання.

Керівництво c #, перетворення типів

Важливо відзначити, що в C # передбачено ключове слово unchecked. яке дозволяє відключити видачу пов'язаного з переповненням виключення в окремих випадках.

Отже, щоб підвести підсумок по використанню в C # ключових слів checked і unchecked, слід зазначити, що за замовчуванням арифметичне переповнення в виконуючою середовищі .NET ігнорується. Якщо необхідно обробити окремі оператори, то повинно використовуватися ключове слово checked, а якщо потрібно перехоплювати всі пов'язані з переповненням помилки в додатку, то знадобиться активізувати прапор / checked. Що стосується ключового слова unchecked, то його можна застосовувати при наявності блоку коду, в якому переповнення є допустимим (і, отже, не повинно призводити до генерації виключення під час виконання).

Роль класу System.Convert

На завершення теми перетворення типів даних варто відзначити, що в просторі імен System є клас Convert. який теж може застосовуватися для розширення і звуження даних:

Одна з переваг підходу із застосуванням класу System.Convert пов'язано з тим, що він дозволяє виконувати перетворення між типами даних нейтральним до мови чином (наприклад, синтаксис приведення типів в Visual Basic повністю відрізняється від пропонованого для цієї мети в C #). Однак, оскільки в C # є операція явного перетворення, використання класу Convert для перетворення типів даних зазвичай є справою смаку. )