Упакування та розпакування. Необхідність (переваги) застосування узагальнень. Підвищення типової безпеки з допомогою узагальнень
Зміст
- 1. Поняття упакування (boxing) та розпакування (unboxing)
- 2. Яка відмінність між використанням узагальнень та приведенням до типу object? Демонстрація переваг застосування узагальнень. Приклад
- Зв’язані теми
Пошук на інших ресурсах:
1. Поняття упакування (boxing) та розпакування (unboxing)
Як відомо, в .NET Framework усі базові типи (int, double, char тощо) представлені відповідним класом або структурою (Integer, Double, Char тощо) в загальній ієрархічній структурі класів. У вершині цієї структури лежить тип Object, до якого можна також звертатись за іменем object. Це означає, що допускається оголошувати змінну типу Object та використовувати її для роботи з будь-яким типом як показано нижче
... // Можна працювати також через базовий клас Object Object a; object b; a = 25; // присвоюється значення типу int b = "bestprog"; // присвоюється значення типу string Console.WriteLine("a = {0}", a); // a = 25 Console.WriteLine("b = {0}", b); // b = bestprog // Змінній a знову присвоюється значення іншого типу double a = 2.88; Console.WriteLine("a = {0}", a); // a = 2.88 ...
Допускається також використовувати змінну типу object в правій частині оператора присвоєння:
... // Змінна типу object object c; c = 'A'; // присвоюється значення char char cc; // Змінна типу char cc = (char)c; // тут потрібне явне приведення типів, інакше помилка на етапі компіляції Console.WriteLine("cc = {0}", cc); // cc = A ...
Але в цьому випадку потрібно вказувати явне приведення типів, як видно з рядка
...
cc = (char)c;
...
інакше буде помилка на етапі компіляції.
Якщо змінна типу object використовується в лівій частині оператора присвоєння, то компілятор виконує так зване упакування. Якщо змінна або значення типу object використовується в правій частині оператора присвоєння, то компілятор виконує розпакування.
Таким чином можна дати наступні визначення. Упакування – це є процес збереження значення простого типу (int, char, double …) в екземплярі об’єкту (object). Розпакування – це є процес витягування упакованого значення (int, double, char …) з об’єкту (object). Наступний приклад демонструє відмінність між цими термінами:
... object a; // тип int упаковується в тип object a = 300; // упакування: object <= int int b; b = (int)a; // розпакування: int <= object ...
⇑
2. Яка відмінність між використанням узагальнень та приведенням до типу object? Демонстрація переваг застосування узагальнень. Приклад
Як було сказано в п. 1 у програмах на C# можна оголошувати посилання на тип Object, звертаючись до імен object або Object. Завдяки успадкуванню, змінним типу Object може бути присвоєне значення будь-яких успадкованих типів (дивіться п. 1).
Виходячи з вищесказаного, можна прийти до висновку, що використання типу Object може замінити узагальнення. Тоді виникає слушне запитання: навіщо використовувати узагальнення, якщо вони цілком можуть бути замінені типом object?
Використання узагальнень замість використання типу object дає наступні переваги:
- відсутність явного приведення типу в операторі присвоєння при використанні узагальнень;
- забезпечення типової безпеки. Помилка неправильного приведення типів генерується вже на етапі компіляції а не на етапі виконання програми;
- підвищення продуктивності. Для типу object операція присвоєння виконується довше, оскільки відбувається упакування та розпакування.
У наступних пунктах ці переваги розглядаються більш детально.
⇑
2.1. Перевага 1. Відсутність явного приведення типу
Якщо використовується узагальнення, то не потрібно виконувати явне приведення типів в операції присвоєння як показано на рисунку 1.
Рисунок 1. Відмінність в явному приведенні до типу int між узагальненням та типом object
⇑
2.2. Перевага 2. Забезпечення типової безпеки в узагальненнях
При використанні класу object в якості типу можна допустити помилку, яка на етапі компіляції не буде виявлена. Ця помилка виявиться на етапі виконання, що є неприйнятним.
На рисунку 2 реалізовано такі самі класи як на рисунку 1. Однак, у функції main(), для обох класів здійснюється спроба встановити значення типу double.
У випадку з класом ObjectClass помилки на етапі компіляції не виникає. Ця помилка викличе виключну ситуацію на етапі виконання.
У випадку з класом GenClass<T> помилка буде визначена на етапі компіляції. Це пов’язано з тим, що створюється типізований код з прив’язкою до типу int. В цьому коді помилки визначаються на етапі компіляції. Це є основною перевагою узагальнень, які підвищують типову безпеку.
Рисунок 2. Особливості виявлення помилки компілятором для узагальненого та неузагальненого класу
⇑
2.3. Перевага 3. Підвищення продуктивності
Використання узагальнених класів дає більшу продуктивність (швидкодію) у порівнянні з неузагальненими. При присвоєнні значення типу object іншим типам і навпаки, компілятор виконує упакування та розпакування (дивіться п. 1). Цей процес вимагає більше часових затрат ніж використання узагальнень. У випадку з узагальненнями формується типізований код з прив’язкою до конкретного типу, який виконується швидше.
Рисунок 3 відображає оголошення двох класів ObjectClass та GenClass. У функції main() виділено фрагменти коду, в яких проявляється відмінність у продуктивності між об’єктами (object) та узагальненнями.
Рисунок 3. Відмінність в продуктивності виконання коду між узагальненим класом та класом типу object. Операція присвоєння для узагальнених класів виконується швидше
⇑
Зв’язані теми
- Узагальнення. Основні поняття. Узагальнені класи та структури
- Узагальнені інтерфейси. Синтаксис оголошення. Реалізація узагальнених інтерфейсів у класах
- Узагальнені методи в класах. Синтаксис оголошення. Способи виклику
- Узагальнені делегати
⇑