call void [mscorlib]System.Console::WriteLine(string, object)
…
}
Обратите внимание на то. что перед обращением к ArrayList.Add размещенное в стеке значение System.Int32 преобразуется в объект, чтобы передать требуемый System.Object. Также заметьте, что при чтении из ArrayList с помощью индексатора типа (что отображается в скрытый метод get_Item) объект System.Object восстанавливается в System.Int32 только для того, чтобы снова стать объектным образом при передаче методу Console.WriteLine.
Проблемы создания объектных образов и восстановления значений
Операции создания объектных образов и восстановления из них значений очень удобны с точки зрении программиста, но такой упрощенный подход при обмене элементами стека и динамической памяти имеет свои специфические проблемы производительности и не гарантирует типовой безопасности. Чтобы понять проблемы производительности, рассмотрим следующие шаги, которые приходится выполнять при создании объектного образа и восстановлении значения обычного целого числа.
1. Новый объект нужно разместить в управляемой динамической памяти.
2. Значение размещенных в стеке данных нужно записать в соответствующее место в памяти.
3. При восстановлении значений, сохраненного в объекте, размещенном в динамической памяти, это значение нужно снова вернуть в стек.
4. Неиспользуемый объект в управляемой динамической памяти (в конце концов) должен быть уничтожен сборщиком мусора.
В нашей ситуации метод Main с точки зрения производительности не имеет никаких проблем, но соответствующие проблемы появятся, когда ArrayList будет содержать тысячи целых значений, если вашей программе придется регулярно их обрабатывать.
Теперь рассмотрим проблему отсутствия: типовой безопасности в отношении операции восстановления значений из объектного образа. Вы знаете, что для восстановления значения в рамках синтаксиса C# используется оператор преобразования. Но каким будет это преобразование – успешным или неудачным, – выяснится только
static void Main(string[] args) {
…
// Ой! Исключение времени выполнения!
Console.WriteLine("Значение вашего int: {0}", (short)myInts[0]);
Console.ReadLine;
}
В идеальной ситуации компилятор C# должен решать проблемы некорректных операций восстановления из объектного образа во время компиляции, а не в среде выполнения. В связи с этим, в
Типовая безопасность и строго типизованные коллекции
В мире .NET, существовавшем до появления версии 2.0, программисты попытались решить проблемы типовой безопасности с помощью построения пользовательских строго типизованных коллекций. Для примера предположим, что вы хотите создать пользовательскую коллекцию, которая сможет содержать только объекты типа Person (персона).
public class Person {
// Определены открытыми для простоты.
public int currAge;
public string fName, lName;
public Person{}
public Person(string firstName, string lastName, int age) {
currAge = age;
fName = firstName;
lName = lastName;
}
public override string ToString {
return string.Format("Возраст {0}, {1} равен (2}", lName, fName, currAge);
}
}
Чтобы построить коллекцию персон, можно определить член-переменную
System.Collections.ArrayList в рамках класса PeopleCollection и настроить все члены на работу со строго типизованными объектами Person, а не с общими объектами System.Object.
public class PeopleCollection: IEnumerable {
private ArrayList arPeople = new ArrayList;
public PeopleCollection{}
// Преобразование для вызывающей стороны.
public Person GetPerson(int pos) { return (Person)arPeople[pos]; }
// Вставка только типов Person.