
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.52] |
![]() |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
||||||||||||||||||||||||||||||||||||||||||
|
Visual Basic
User Defined Types Типы данных определяемые пользователем Создание и использование UDT – создание Кроме базовых типов данных: Integer, Long, String и т.д., Visual Basic поддерживает типы данных, определяемые пользователем – User Defined Types (далее UDT). Комбинируя переменные различных типов, можно создать UDT (известный, в языке программирования Cи, как структура). UDT используется, для создания переменной, содержащей несколько взаимосвязанных частей информации. Для создания UDT используется ключевое слово Type: ![]() ![]() 'Синтаксис VB [Private | Public] Type TypeName Element1 [([Size])] As DataType [Element2 [([Size])] As DataType] End Type Определение общего (Public) UDT, возможно только в секции (General) (Declarations) модуля. В этом случае, тип будет доступен во всех процедурах всех форм, модулей и модулей классов. Для определения UDT в форме или модуле класса, следует использовать ключевое слово Private, поскольку объявление общего типа в данной ситуации не допускается. При этом, область видимости такого типа, будет ограничена контейнером, где он объявлен. ![]() ![]() Private Type MyDataType или ![]() ![]() Public Type MyDataType Например, можно создать UDT, содержащий информацию о компьютере: ![]() ![]() ' Декларация в стандартном модуле Private Type SystemInfo CPU As Variant Memory As Long VideoColors As Integer Cost As Currency PurchaseDate As Variant End Type UDT – объявление переменных Определив UDT, вы можете использовать его для объявления переменных этого типа. Эти переменные могут быть локальными, глобальными или переменными контейнера: ![]() ![]() Dim MySystem As SystemInfo Private YourSystem As SystemInfo Таблица 1. Контейнеры, где можно объявить UDT и его переменную.
Примечание! UDT, объявленный без ключевого слова, по умолчанию считается объявленным, как Public. Если требуется UDT уровня модуля или модуля класса, его следует объявлять, используя ключевое слово Private. UDT – присвоение и получение значений Доступ к элементам переменной UDT осуществляется, по аналогии с доступом к свойствам, путем указания точки после имени переменной. ![]() ![]() MySystem.CPU = "486" If MySystem.PurchaseDate > #1/1/92# Then При этом переменные одинакового типа можно присваивать не поэлементно, а напрямую: ![]() ![]() YourSystem = MySystem UDT – содержащий массив UDT, может содержать обычный (фиксированного размера) массив: ![]() ![]() Type SystemInfo CPU As Variant Memory As Long DiskDrives(25) As String ' Фиксированный массив VideoColors As Integer Cost As Currency PurchaseDate As Variant End Type А также, может содержать динамический массив. ![]() ![]() Type SystemInfo CPU As Variant Memory As Long DiskDrives() As String ' Динамический массив VideoColors As Integer Cost As Currency PurchaseDate As Variant End Type Доступ к значениям элементов массива, UDT осуществляется, по аналогии с доступом к свойству объекта. ![]() ![]() Dim MySystem As SystemInfo ReDim MySystem.DiskDrives(3) MySystem.DiskDrives(0) = "1.44 MB" Также, можно объявить массив UDT: ![]() ![]() Dim AllSystems(100) As SystemInfo Для доступа к элементам этого типа, следуем тем же правилам. ![]() ![]() AllSystems(5).CPU = "386SX" AllSystems(5).DiskDrives(2) = "100M SCSI" UDT – аргумент процедуры UDT можно использовать, как один из аргументов процедуры. ![]() ![]() Sub FillSystem (SomeSystem As SystemInfo) SomeSystem.CPU = lstCPU.Text SomeSystem.Memory = txtMemory.Text SomeSystem.Cost = txtCost.Text SomeSystem.PurchaseDate = Now End Sub Примечание! При использовании UDT, в качестве аргумента процедуры в модуле формы, процедура должна быть объявлена, как Private. UDT, можно использовать в качестве возвращаемого значения функции, а пользовательскую переменную в качестве одно из аргументов процедуры. UDT всегда передаются по ссылке (ByRef), так что процедура может изменить аргумент и вернуть его в вызываемую функцию. Примечание! Поскольку UDT всегда передается по ссылке, все данные, будут переданы и получены без проблем. Для UDT, содержащих большие массивы данных, это может привести к снижению производительности, особенно в архитектуре клиент-серверных приложений, где процедура может быть запущена на удаленной машине. В такой ситуации, лучше, принимать и передавать только необходимые данные полей UDT. UDT – содержащий объект UDT, может содержать объект. ![]() ![]() Private Type AccountPack frmInput as Form dbPayRollAccount as Database End Type Примечание! Поскольку тип Variant может хранить различные типы данных, массив Variant может быть использован во многих ситуациях, где можно использовать UDT. Массив Variant, на самом деле более гибкий, чем UDT, потому что можно изменить тип данных, хранящихся в каждом его элементе в любое время, и можно сделать массив динамическим, и изменять размер по мере необходимости. Однако, массив Variant, всегда использует больше памяти, чем эквивалентные UDT. UDT – составной UDT, может быть составным. В этом случае важна последовательность определения UDT. Сначала нужно определить основной UDT, который будет использоваться далее в составных UDT. Если не соблюдать это правило, то после запуска программы появится сообщение об ошибке. Ниже приводится пример использования составных UDT: ![]() ![]() Type DriveInfo Type As String Size As Long End Type Type SystemInfo CPU As Variant Memory As Long DiskDrives(26) As DriveInfo Cost As Currency PurchaseDate As Variant End Type Dim AllSystems(100) As SystemInfo AllSystems(1).DiskDrives(0).Type = "Floppy" UDT, рекомендуется использовать при обработке данных неизменной структуры. UDT – копирование Рассмотрим оператор Visual Basic – LSet ![]() ![]() 'Синтаксис VB LSet StringVariable = StringExpression LSet – выравнивает строку по левой стороне, при присваивании ей значения, меньшего по размеру, чем исходная строка. Вместо строк могут использоваться UDT. Вспомним базовые типы данных Visual Basic Таблица 2. Базовые типы данных Visual Basic
Определимся со значениями некоторых типов данных. Рассмотрим следующий пример: ![]() ![]() 'Объявление UDT Private Type TypeExempleOne Element_1 As Integer Element_2 As Long End Type Private Type TypeExempleTwo Element_1 As Integer Element_2 As Long End Type Private Sub CopyUDT() 'Объявление переменных UDT Dim teo As TypeExempleOne Dim tet As TypeExempleTwo 'Присваивание значений teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = 22 tet.Element_2 = 222222 'Выводим на печать присвоенные значения Debug.Print "Значения до копирования" Debug.Print "teo.Element_1 = " & teo.Element_1, "teo.Element_2 = " & teo.Element_2 Debug.Print "tet.Element_1 = " & tet.Element_1, "tet.Element_2 = " & tet.Element_2 'Копируем один UDT в другой LSet tet = teo 'Выводим на печать значения после копирования Debug.Print "Значения после копирования" Debug.Print "teo.Element_1 = " & teo.Element_1, "teo.Element_2 = " & teo.Element_2 Debug.Print "tet.Element_1 = " & tet.Element_1, "tet.Element_2 = " & tet.Element_2 End Sub В окне Immediate мы увидим следующие значения: Цитата Значения до копирования teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = 22 tet.Element_2 = 222222 Значения после копирования teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = 11 tet.Element_2 = 1111111 При копировании UDT надо придерживаться следующих правил: Немного изменим пример: ![]() ![]() 'Объявление пользовательских типов Private Type TypeExempleOne Element_1 As Integer Element_2 As Long End Type Private Type TypeExempleTwo Element_1 As Boolean Element_2 As Long End Type Private Sub CopyUDT() 'Объявление переменных пользовательского типа Dim teo As TypeExempleOne Dim tet As TypeExempleTwo 'Присваивание значений teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = False tet.Element_2 = 222222 'Выводим на печать присвоенные значения Debug.Print "Значения до копирования" Debug.Print "teo.Element_1 = " & teo.Element_1, "teo.Element_2 = " & teo.Element_2 Debug.Print "tet.Element_1 = " & tet.Element_1, "tet.Element_2 = " & tet.Element_2 'Копируем один тип данных в другой LSet tet = teo 'Выводим на печать значения после копирования Debug.Print "Значения после копирования" Debug.Print "teo.Element_1 = " & teo.Element_1, "teo.Element_2 = " & teo.Element_2 Debug.Print "tet.Element_1 = " & tet.Element_1, "tet.Element_2 = " & tet.Element_2 End Sub В окне Immediate мы увидим следующие значения: Цитата Значения до копирования teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = False tet.Element_2 = 222222 Значения после копирования teo.Element_1 = 11 teo.Element_2 = 1111111 tet.Element_1 = True tet.Element_2 = 1111111 В первом примере, мы копировали полностью идентичные UDT, в изменённом – скопировали в Boolean переменную, значение тип Integer. Как видно из таблицы 2, тип Boolean занимает в памяти 2 байта. Тип данных Integer – 2 байта. Тип данных Long занимает в памяти 4 байта. Значит, общий размер каждого UDT, составляет 6 байт, мы не нарушили правил при копировании. Соответственно, зная размеры занимаемой памяти, базовых типов Visual Basic, можно легко определиться с копированием пользовательских типов данных. Например: Long(4 байта) = двухразрядный массив Integer(4 байт) Необходимое послесловие. В первоначальной версии, статья заканчивалась описанием базового типа Variant. Но его расширенное описание, вылилось в статью, по размерам превышающую настоящую. Статья о типе Variant находиться в завершающей стадии и скоро будет представлена. С уважением Diamock. |
![]() |
Сообщ.
#2
,
|
|
В целом, неплохо. Что не понравилось:
Упомянут, но не раскрыт тип Variant. Думаю, некоторых бы заинтересовало его внутреннее устройство Не затронута тема копирования UDT, посредством LSet, с оговорками о нюансах |
Сообщ.
#3
,
|
|
|
Цитата Diamock @ Всегда считал, что дим на уровне модуля - синоним привата Примечание! Пользовательский тип, объявленный с помощью ключевого слова Dim, по умолчанию считается объявленным, как Public. Если требуется пользовательский тип уровня модуля или модуля класса, его следует объявлять, используя ключевое слово Private. ![]() Видимо, имелось ввиду, что если при объявлении типа не указано, приват он или паблик, то считается пабликом. |
![]() |
Сообщ.
#4
,
|
|
Diamock, можешь учесть мои замечания?
|
Сообщ.
#5
,
|
|
|
Цитата B.V. @ Diamock, можешь учесть мои замечания? Конечно, сейчас разбираюсь с LSet и типом Variant. Как всё отложется в голове по полочкам, и примеры будут работать - дополню и исправлю. |
![]() |
Сообщ.
#6
,
|
|
Цитата Diamock @ Копировать один тип пользовательских данных в другой, можно при условии, что типы соответствующих элементов совпадают. Нет, копировать можно всегда. Но адекватный результат будет только при идентичности размеров полей, и общего размера структуры. Идентичность типов полей не обязательна. Так, к примеру, Integer поле прекрасно ляжет на массив из двух байт. Цитата Diamock @ В методе Invoke() стоит предусмотреть проверку корректности типа значения Как не знающий про IDispatch интерфейс человек поймет, о чем это ты? Да и такое углубление в COM здесь, по-моему, неуместно |
Сообщ.
#7
,
|
|
|
Цитата B.V. @ Как не знающий про IDispatch интерфейс человек поймет, о чем это ты? Да и такое углубление в COM здесь, по-моему, неуместно Тема типа данных Variant, меня очень заинтересовала, поэтому у меня в планах (в далёких, как только разберусь с сабклассингом, хуками и TLB) - написать расширенную статью о типе Variant. Также, продолжу изыскания о применении типа Variant в Visual Basic, и внесу изменения в статью. Статью, по поводу копирования, я подправлю, после экспериментов с LSet. |
![]() |
Сообщ.
#8
,
|
|
Цитата Diamock @ Тема типа данных Variant, меня очень заинтересовала Тогда тебя, вероятно, заинтересуют и другие OLE-Automation типы, как SAFEARRAY. На RSDN уже есть подробная статья по этим двум комплексным типам: http://www.rsdn.ru/article/com/varsafearr.xml Только просьба, если вздумаешь писать аналогичную, то не копипасть инфу оттуда, а попытайся изложить от себя Цитата Diamock @ и внесу изменения в статью Как внесешь, дай знать. Если ни у меня, и ни у кого-нибудь еще из участников претензий не будет, отправлю в ФАК Давненько у нас такой подробный материал не добавлялся ![]() |
Сообщ.
#9
,
|
|
|
B.V. Спасибо. Учту все замечания.
![]() |
Сообщ.
#10
,
|
|
|
А мою ремарку ты чего проигнорировал?
Цитата Diamock @ Ну-ка, покажи, как объявить пользовательских тип с помощью дима? Примечание! Пользовательский тип, объявленный с помощью ключевого слова Dim, по умолчанию считается объявленным, как Public. Если требуется пользовательский тип уровня модуля или модуля класса, его следует объявлять, используя ключевое слово Private. |
Сообщ.
#11
,
|
|
|
Цитата Артур @ А мою ремарку ты чего проигнорировал? Цитата Diamock @ Ну-ка, покажи, как объявить пользовательских тип с помощью дима?Примечание! Пользовательский тип, объявленный с помощью ключевого слова Dim, по умолчанию считается объявленным, как Public. Если требуется пользовательский тип уровня модуля или модуля класса, его следует объявлять, используя ключевое слово Private. Уважаемый Артур! Ваше замечание, я конечно не проигнорировал. Объявление с помощью Dim - вызывает ошибку ![]() ![]() С уважением... |
Сообщ.
#12
,
|
|
|
Здравствуйте Уважаемые!
Статья, отредактирована и частично переписана с учётом всех пожеланий. С уважением... |
Сообщ.
#13
,
|
|
|
Цитата Diamock @ String 10 байтов +1 байт на символ в обычной кодировке и 2 байта в кодировке Unicode Как бы VB6 всегда использует Unicode и не понял как получилось 10 байт? 4 байта на длину строки + 2 байта на нул-терминэйт строки = 6 байт + по 2 байта на каждый символ. Или только если учитывается указатель на переменную стринг |
Сообщ.
#14
,
|
|
|
VSHome
Цитата VSHome @ Как бы VB6 всегда использует Unicode и не понял как получилось 10 байт? 4 байта на длину строки + 2 байта на нул-терминэйт строки = 6 байт + по 2 байта на каждый символ. Или только если учитывается указатель на переменную стринг Не понял вопроса? ![]() |
Сообщ.
#15
,
|
|
|
"как получилось 10 байт?"
|