Структурные типы
Традиционно в объектно-ориентированных языках возникало немало проблем с простейшими типами данных — такими, как обычные целые числа. Дело в том, что в объектно-ориентированном языке все данные должны быть объектами. С другой стороны, создание объекта сопряжено с определенными затратами на выполнение служебных операций (таких, как выделение блока памяти для объекта). Обработка сообщения «сложить» также уступает по скорости простой математической операции сложения и т. д. Стоит добавить, что в языках с автоматической сборкой мусора некоторое время расходуется на уничтожение неиспользуемых объектов.
Ранние объектно-ориентированные языки пошли по самому прямолинейному пути. Скажем, в Smalltalk все данные интерпретировались как объекты. В результате такие языки работали медленнее, чем языки с разделением примитивных типов и объектов. С другой стороны, подобное разделение приводило к усложнению программ, поскольку программный код, работавший с числами, приходилось отделять от кода, работавшего с объектами. Чтобы интерпретировать число в объектном контексте, его приходилось «заворачивать» в объект. Например, в Java сохранение числа в эквиваленте динамического массива выглядело примерно так:
anArrayList.Add(Integer(5));
Число 5 «заворачивалось» в объект Integer. Такие программы плохо читались и медленно работали.
В .NET Framework были объединены лучшие стороны обоих решений. В общем случае числа интерпретируются как примитивные типы, но при "необходимости они автоматически интерпретируются как объекты. Таким образом, для обычного числового литерала можно вызвать метод или занести его в хэш-таблицу без дополнительных усилий. Это называется автоматической упаковкой (boxing); обратный процесс называется распаковкой (unboxing).
Для нас, программистов, из этого вытекает важное следствие: хотя в VB .NET все данные являются объектами, не каждая переменная в программе содержит манипулятор блока памяти и создается оператором New.
Разумеется, ничто не дается даром: программисту приходится помнить о различиях между структурными и ссылочными типами. Первое, наиболее очевидное различие заключается в том, что новые экземпляры структурных типов создаются без ключевого слова New. Вам не придется (да и не удастся) использовать конструкции вида Dim a As New Integer(5).
Более серьезное различие связано с передачей переменных процедурам по значению. Как было сказано выше, при передаче изменяемого объекта по значению процедура может изменить состояние объекта. Переданные по значению структурные типы ведут себя вполне традиционно — все изменения теряются при выходе из вызванной процедуры или функции (иногда это называется структурной семантикой в отличие от ссылочной семантики).
Все числовые типы VB .NET являются структурными типами; к этой же категории относится и такой тип, как дата. Как будет показано ниже, VB .NET позволяет определить пользовательские структурные типы, если по соображениям быстродействия вы хотите свести к минимуму затраты на работу с объектами или же предпочитаете работать с объектами, обладающими структурной семантикой.
Function IsValueType(ByVal foo As Object)As Boolean
If TypeOf (foo)Is System.ValueType Then
Return True Else
Return False
End If
End Function
Для объектов структурного типа оператор Equal s всегда возвращает True, если структурные объекты содержат одинаковые данные. Синтаксис вызова выглядит так:
a..Fquals(b)
Учтите, что для ссылочных типов этот принцип в общем случае не выполняется. Например, два массива могут содержать одинаковые элементы, но равными при этом они не считаются.
В VB .NET структурные типы делятся на две категории: структуры и перечисляемые типы. Мы начнем с перечисляемых типов, а затем перейдем к структурам, которые представляют собой «облегченные» варианты объектов.