class BoxingDemo {
static void Main() {
int x;
object obj;
x = 10;
obj = x; // упаковать значение переменной х в объект
int у = (int)obj; // распаковать значение из объекта, доступного по
// ссылке obj, в переменную типа int
Console.WriteLine(у);
}
}
В этом примере кода выводится значение 10. Обратите внимание на то, что значение переменной х упаковывается в объект простым его присваиванием переменной obj, ссылающейся на этот объект. А затем это значение извлекается из объекта, доступного по его ссылке obj, и далее приводится к типу int.
Ниже приведен еще один, более интересный пример упаковки. В данном случае значение типа int
передается в качестве аргумента методу Sqr()
, который, в свою очередь, принимает параметр типа object
.
// Пример упаковки при передаче значения методу.
using System;
class BoxingDemo {
static void Main() {
int x;
x = 10;
Console.WriteLine("Значение x равно: " + x);
// значение переменной x автоматически упаковывается
// когда оно передается методу
Sqr().
x = BoxingDemo.Sqr(x) ;
Console.WriteLine("Значение x в квадрате равно: " + x);
}
static int Sqr(object о) {
return (int)о * (int)о;
}
}
Вот к какому результату приводит выполнение этого кода.
Значение х равно: 10
Значение х в квадрате равно: 100
В данном примере значение переменной х автоматически упаковывается при передаче методу Sqr()
.
Упаковка и распаковка позволяют полностью унифицировать систему типов в С#. Благодаря тому что все типы являются производными от класса object
, ссылка на значение любого типа может быть просто присвоена переменной ссылочного типа object
, а все остальное возьмут на себя упаковка и распаковка. Более того, методы класса object
оказываются доступными всем типам, поскольку они являются производными от этого класса. В качестве примера рассмотрим довольно любопытную программу.
// Благодаря упаковке становится возможным вызов
//методов по значению!
using System;
class MethOnValue {
static void Main() {
Console.WriteLine(10.ToString() ) ;
}
}
В результате выполнения этой программы выводится значение 10. Дело в том, что метод ToString() возвращает строковое представление объекта, для которого он вызывается. В данном случае строковым представлением значения 10 как вызывающего объекта является само значение 10!
Если object
является базовым классом для всех остальных типов и упаковка значений простых типов происходит автоматически, то класс object можно вполне использовать в качестве "универсального" типа данных. Для примера рассмотрим программу, в которой сначала создается массив типа object, элементам которого затем присваиваются значения различных типов данных.
// Использовать класс object для создания массива "обобщенного" типа.
using System;
class GenericDemo {
static void Main() {
object[] ga = new object[10];
// Сохранить целые значения,
for (int i=0; i < 3; i++) ga[i] = i;
// сохранить значения типа double
for (int i=3; i < 6; i++)
ga[i] =(double) i / 2;
// сохранить две строки, а также значения типа bool и char
ga[6] = "Привет";
ga[7] = true;
ga[8] = 'X';
ga[9] = "Конец";
for(int i = 0; i < ga.Length; i++)
Console.WriteLine("ga[" + i + "]: " + ga[i] + " ");
}
}
Выполнение этой программы приводит к следующему результату.
ga[0] : 0
ga[1] : 1
ga[2] : 2
ga[3] : 1.5
ga[4] : 2
ga[5] : 2.5
ga[6] : Привет
ga[7] : True
ga[8] : X
ga[9] : Конец