public class System.Collections.ArrayList: object, System.Collections.IList, System.Collections.ICollection, System.Collections.IEnumerable, ICloneable {
…
public virtual int Add(object value);
public virtual void Insert(int index, object value);
public virtual void Remove(object obj);
public virtual object this[int index] {get; set;}
}
Как видите, эти члены действуют на типы System.Object. Поскольку все, в конечном счете, получается из этого общего базового класса, следующий программный код оказывается вполне корректным.
static void Main(string [] args) {
…
ArrayList myInts = new ArrayList();
myInts.Add(88);
myInts.Add(3.33);
myInts.Add(false);
}
Но теперь с учетом вашего понимания ссылочных типов и типов, характеризуемые значением, вы можете спросить: что же на самом деле размещается в ArrayList? (Ссылки? Копии ссылок? Копии структур?) Как и в случае, с рассмотренным выше методом UseThisObject(), должно быть ясно, что каждый из типов данных System.Int32 перед размещением в ArrayList в действительности приводится к объектному типу. Чтобы восстановить элемент из типа ArrayList, требуется выполнить соответствующую операцию восстановления.
static void BoxAndUnboxInts() {
// "Упаковка" данных int в ArrayList.
ArrayList myInts = new ArrayList();
myInts.Add(88);
myInts.Add(3.33);
myInts.Add(false);
// Извлечение первого элемента из ArrayList.
int firstItem = (int)myInts[0];
Console.WriteLine("Первым элементом является {0}", firstItem);
}
Без сомнения, операции приведения к объектному типу и восстановления из объектного образа требуют времени и, если эти операций использовать без ограничений, это может влиять на производительность приложения. Но с использованием такого подхода .NET вы можете симметрично работать с типами характеризуемыми значением, и со ссылочными типами.
Замечание. В C# 2.0 потери производительности из-за приведения к ссылочному типу и восстановления из объектного образа можно нивелировать путем использования
Восстановление из объектного образа для пользовательских типов
Когда методу, предполагающему получение экземпляров System.Object, передаются пользовательские структуры или перечни, тоже происходит их приведение к объектному типу, Однако после получения входного параметра вызванным методом вы не сможете получить доступ к каким бы то ни было членам структуры (или перечня), пока не выполните операцию восстановлений из объектного образа для данного типа. Вспомним структуру МуРoint, определенную в этой главе выше.
Struct MyPoint {
public int x, у;
}
Предположим, что вы посылаете переменную MyPoint новому методу с именем UseBoxedMyPoint().
static void Main(string[] args) {
…
MyPoint p;
p.x = 10;
p.y = 20;
UseBoxedMyPoint(p);
}
При попытке получить доступ к полю данных MyPoint возникнет ошибка компиляции, поскольку метод предполагает, что вы действуете на строго типизованный System.Object.
static void UseBoxedMyPoint(object o) {
// Ошибка! System.Object не имеет членов-переменных
// с именами 'х' и 'у' .
Console.WriteLine ("{0}, {1}", о.х, о.у);
}
Чтобы получить доступ к полю данных MyPoint, вы должны сначала восстановить параметр из объектного образа. Сначала можно использовать ключевое слово C# is для проверки того, что этот параметр на самом деле является переменной MyPoint. Ключевое слово is рассматривается в главе 4, здесь мы только предлагаем пример его использования.
static void UseBoxedMyPoint(object о) {
if (о is MyPoint) {
MyPoint p = (MyPoint)o;
Console.WriteLine ("{0}, {1}", p.x, p.y);
} else Console.WriteLine("Вы прислали не MyPoint.");
}
Исходный код. Проект Boxing размещен в подкаталоге, соответствующем главе 3.
Работа с перечнями .NET