C#. Упакування та розпакування. Необхідність застосування узагальнень

Упакування та розпакування. Необхідність (переваги) застосування узагальнень. Підвищення типової безпеки з допомогою узагальнень


Зміст


Пошук на інших ресурсах:




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.

C#. Узагальнення. Відсутність явного приведення типу

Рисунок 1. Відмінність в явному приведенні до типу int між узагальненням та типом object

 

2.2. Перевага 2. Забезпечення типової безпеки в узагальненнях

При використанні класу object в якості типу можна допустити помилку, яка на етапі компіляції не буде виявлена. Ця помилка виявиться на етапі виконання, що є неприйнятним.

На рисунку 2 реалізовано такі самі класи як на рисунку 1. Однак, у функції main(), для обох класів здійснюється спроба встановити значення типу double.

У випадку з класом ObjectClass помилки на етапі компіляції не виникає. Ця помилка викличе виключну ситуацію на етапі виконання.

У випадку з класом GenClass<T> помилка буде визначена на етапі компіляції. Це пов’язано з тим, що створюється типізований код з прив’язкою до типу int. В цьому коді помилки визначаються на етапі компіляції. Це є основною перевагою узагальнень, які підвищують типову безпеку.

C#. Узагальнення. Особливості виявлення помилки компіляторомРисунок 2. Особливості виявлення помилки компілятором для узагальненого та неузагальненого класу

 

2.3. Перевага 3. Підвищення продуктивності

Використання узагальнених класів дає більшу продуктивність (швидкодію) у порівнянні з неузагальненими. При присвоєнні значення типу object іншим типам і навпаки, компілятор виконує упакування та розпакування (дивіться п. 1). Цей процес вимагає більше часових затрат ніж використання узагальнень. У випадку з узагальненнями формується типізований код з прив’язкою до конкретного типу, який виконується швидше.

Рисунок 3 відображає оголошення двох класів ObjectClass та GenClass. У функції main() виділено фрагменти коду, в яких проявляється відмінність у продуктивності між об’єктами (object) та узагальненнями.

C#. Узагальнення. Продуктивність виконанняРисунок 3. Відмінність в продуктивності виконання коду між узагальненим класом та класом типу object. Операція присвоєння для узагальнених класів виконується швидше

 


Зв’язані теми