Создание нового класса в vba excel - IT Новости из мира ПК
Remkomplekty.ru

IT Новости из мира ПК
22 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Создание нового класса в vba excel

Создание нового класса в vba excel

Создание приложения на vba путем написания процедур и функций стоит называть процедурным программированием. Написание участков кода, называемых процедурами и функциями, которые описывают какое-либо действие, и последующее последовательное исполнение этих кодов, является основным методом программирования на vba. При этом используется доступ к объектной модели Excel или других приложений. Данные и подпрограммы (функции и процедуры) функционально не связаны между собой. Это значит, что объявляя переменную «длина хвоста» на уровне модуля, нельзя задать ей различные значения для двух процедур.

При объектно-ориентированном программировании (ООП) подход иной. Данные и подпрограммы связаны между собой и описываются в классе.

Класс – сложный тип данных, в котором описывается структура объекта. Объект – основной строительный материал для написания программ. Отличные представители объектов – форма, лист, книга, диаграмма. Объект, созданный на основе класса, можно называть экземпляром класса.

Класс имеет следующую структуру:

Поле – элемент класса для хранения данных,

Свойство – элемент класса для хранения данных с возможностью их обработки,

Метод – аналог процедуры или функции,

Событие – сигнал при изменении состояния объекта, например исполнения метода или изменения данных.

Из всех принципов ООП в vba реализуемы только два: Абстрагирование и инкапсуляция.

Инкапсуляция позволяет скрыть механизм работы класса, оставив открытыми для других процедур только необходимые для работы с экземпляром класса.
Абстракция позволяет создать объект, наиболее приближенный к некомпьютерному прототипу. Например, создать объект «Кошка» со свойствами «количество лап» и «цвет хвоста».

Для создания класса в vba редакторе выберите в меню Insert строку Class Module. Назовите созданный класс путем переименования созданного модуля. В файле с примером он называется ExampleClass. А модуль, демонстрирующий использование этого класса называется ExClassManagement. В свойствах класса, кроме имени так же есть параметр Instancing. Указывается, будет ли виден класс из другой книги при установке ссылки на данную книгу. При установке Private (по умолчанию) класс виден только в данной книге, при установке PublicNotCreatable, класс не будет доступен из другой книги, однако экземпляр класса доступен будет, если он создан в данной книге.

Класс — это всего лишь описание объекта. Для использования возможностей класса, необходимо создать экземпляр класса (объект). Существует несколько способов:

Данный способ корректен абсолютно

Способ 2:

Этот способ отличается от первого способа тем, что экземпляр класса объявляется вне процедуры и работать с ним можно во всех процедурах модуля. При замене Dim на Public экземпляр класса доступен во всем проекте, если объявляется вне объектного модуля.

Экземпляр класса объявляется с событиями, и если в классе описаны события объекта, они будут доступны. Работает только при объявлении в объектном модуле (модуль класса, формы, листа, книги)

Способ 4:

Так называемый неявный метод создания экземпляра класса. В этом случае объект создается при первом обращении к переменной cl. Наверное, предпочтительнее сначала объявлять переменную (выделяется память), а затем явно создавать объект.

Естественно, после использования экземпляра класса, необходимо очистить память. Делается это одним способом:

Если не деинициализировать экземпляр класс, то ничего глобально страшного происходить в современных офисных пакетах не будет. Но делать это нужно.

Созданный класс ExampleClass не имеет полей, свойств, методов, событий, поэтому и созданный на его основе объект (экземпляр класса) cl, так же бесполезен.

Поля это переменные класса, объявленные в его модуле. Поля бывают закрытые и открытые. Доступ к закрытым полям возможен только внутри модуля класса. Открытое поле, по сути – свойство класса, и при создании экземпляра класса оно будет доступно.

И теперь свойство Head доступно у экземпляра класса cl.

В него можно записать

Создать поле с пользовательским типом данных не удастся.

Поля используются для хранения данных в объекте. Данные будут доступны, пока объект существует. Однако нельзя указать значение по-умолчанию для поля и нельзя сделать поле только для чтения.

Свойство это способ доступа к данным внутри объекта. Выглядят как поля, однако, это функции (назовем их методами). Называются они Property Get для чтения данных из объекта, и Property Let для записи данных в объект. Есть еще третье Property Set для установки ссылки на другой объект. Но это можно сделать и при помощи Property Let, поэтому Property Set вещь бесполезная.

Синтаксис Property Get

[Public | Private | Friend] [Static] Property Get имя [(аргументы)] [As тип]

[произвольный код]
[имя=выражение]
[Exit Property]

[произвольный код]
[имя=выражение]
[End Property]

Работа с модулями классов

Многие наверняка слышали про модули классов, но не все их используют. На самом деле довольно многие программирующие на VBA за все время программирования прекрасно обходятся без применения модулей классов. Т.к. VBA не является языком объектно-ориентированного программирования(ООП) в строгом смысле слова, то пользовательские классы здесь не обязательны и как следствие не так уж и часто используются при разработке. Это не значит, что VBA не содержит модулей классов: модули книги, листов, пользовательские формы — все это модули классов. Многие, кстати, используют их даже не зная того, что используют именно модули классов. Т.к. модуль листа, книги и формы — это модуль класса, то почти каждый, кто работал с формой работал с модулем класса. В чем их большая польза — с их помощью можно отслеживать различные события объектов. Для форм это события самой формы или любого её элемента — например CommandButton_Click или TextBox_Change. Но мы сейчас рассмотрим лишь тот тип модулей, который в VBA обычно называют модулем класса — Class Module.

Модуль класса(Class Module) – это модуль, содержащий программные коды, которые реализуют работу пользовательских классов. В подавляющем большинстве случаев создается специально для отслеживания событий различных объектов. Создается так же, как и любой другой объект проекта: в окне проводника объектов щелкаем правой кнопкой мыши на нужном проекте-InsertClass Module

Но прежде чем создать модуль, необходимо понять, что мы будем в нем хранить и для чего он нам. Возьмем для примера самую распространенную проблему: на форме создано несколько ТекстБоксов и необходимо отследить событие ввода данных в эти ТекстБоксы. Обычно делается все просто — для каждого ТекстБокса прописывается отслеживание события:

Private Sub TextBox1_Change() MsgBox «Изменено значение TextBox1» End Sub Private Sub TextBox2_Change() MsgBox «Изменено значение TextBox2» End Sub Private Sub TextBox3_Change() MsgBox «Изменено значение TextBox3» End Sub ‘и т.д.

С одной стороны — все верно. А с другой: что если таких текстбоксов у нас не 3, а 43? Не очень удобно для каждого событие прописывать. Да и читабельность такой «портянки» кода тоже значительно падает.
Или другая ситуация — необходимо «на ходу» создать ТекстБоксы на форме и в дальнейшем отслеживать их события. Как тут быть? Ведь раз ТексБоксов еще нет — то и события в форме для них не создать. Создание для них кодов обработки событий заранее ничего не даст — они не будут связаны с самими объектами, поэтому и пытаться даже не стоит. Почему так — при создании элемента вручную VBE делает за нас всю грязную работу — он сам ассоциирует созданный объект с событиями, предназначенные для него заранее. Если же создать объект программно — то часть грязной работы придется делать самим. И создание модуля класса, с описанием в нем объекта ТекстБокс и его событий, как раз очень даже подойдет.
Рассмотрим сразу оба случая. Что нам для этого потребуется:

  1. для начала создать модуль класса с именем clsmTxtBxes(InsertClass Module)
  2. создать стандартный модуль с именем mMain(InsertModule)
  3. ну и сама форма тоже не лишняя(InsertUserForm). У меня форма называется frmTest.
  4. очень желательно наличие у вас опыта написания хотя бы простейших процедур. Иначе может показаться все очень сложным и непонятным.
Читать еще:  Объекты vba excel

Чтобы было проще вникать советую скачать файл с готовыми кодами:

Tips_Macro_UseClassModules.xls (63,5 KiB, 4 390 скачиваний)

Для начала создадим на нашей форме frmTest 4 ТекстБокса, не меняя их имена(по умолчанию они будут TextBox1, TextBox2, TextBox3, TextBox4). Это для того, чтобы понять как применить модули класса к уже созданным ранее на форме элементам.
Далее в стандартный модуль mMain поместим следующий код:

Option Explicit Public aoTxtBxes(1 To 8) As New clsmTxtBxes Sub Show_Form() frmTest.Show End Sub

aoTxtBxes — массив, который будет содержать до 8 ТекстБоксов. Объявляется как Public (чтобы был доступен из любого модуля проекта. Подробнее в статье: Что такое переменная и как правильно её объявить?). Обращаю внимание, что данный массив объявлен как созданный нами модуль класса — As clsmTxtBxes. Это обязательное условие. Если у вас модуль класса называется ClassModule1, то и объявлять aoTxtBxes следует соответственно:

Public aoTxtBxes(1 To 8) As New ClassModule1

но я не приветствую подобный подход, т.к. имя ClassModule1 ни о чем нам не говорит, в то время как clsmTxtBxes сразу дает понять, что там мы обрабатываем ТекстБоксы. Хотя это дело вкуса. Если в одном модуле класса собраны различные событийные процедуры для разных типов( TextBox , ComboBox , ListBox и т.д.) — то конечно, имя лучше дать более общее.
Теперь в созданный модуль класса clsmTxtBxes запишем создание объекта и код, который хотим применить для всех наших ТекстБоксов:

Option Explicit Public WithEvents oTxtBx As MSForms.TextBox ‘событие изменения текста в TextBox-ах Private Sub oTxtBx_Change() MsgBox «Вы изменили значение » & oTxtBx.Name, vbInformation, «Информационное окно» End Sub

Public WithEvents oTxtBx As MSForms.TextBox — создаем объект типа ТекстБокс с отслеживанием его событий. Идентификатором объекта с отслеживанием событий служит оператор WithEvents (может применяться только в модулях классов).
Если необходимо отследить изменения не TextBox, а ComboBox, то соответственно объявляем объект нужного типа:
Public WithEvents oCmbBx As MSForms.ComboBox
Сами события для контролов не берутся из головы и не пишутся вручную — они уже есть и следует использовать именно те, которые доступны. Чтобы для конкретного элемента создать событие, необходимо перейти в модуль класса, вверху в левой части выбрать из списка нужный объект(в нашем случае это oTxtBx) и после этого в правом списке выбрать событие(в этом списке перечисляются все процедуры, доступные для выбранного объекта):

Для выбранного события в модуле будет автоматически создана новая процедура.
Процедуры, события для которых уже созданы, выделяются в списке жирным шрифтом и при выборе их из списка происходит переход в процедуру выбранного события.

Завершающий этап — создаем код в модуле формы frmTest , который создаст недостающие ТекстБоксы и свяжет их и ранее созданные с модулем класса:

Option Explicit Private Sub UserForm_Initialize() Dim i As Integer ‘Присваиваем последовательно значениям массива aoTxtBxes значения объектов, существующих на форме For i = 1 To 4 Set aoTxtBxes(i).oTxtBx = Me.Controls(«TextBox» & i) Next i ‘создаем 4 своих TrxtBox-а помимо имеющихся на форме и так же заносим в массив aoTxtBxes For i = 5 To 8 Set aoTxtBxes(i).oTxtBx = Me.Controls.Add(«Forms.TextBox.1», «TextBox» & i) ‘задаем позицию нового TextBox aoTxtBxes(i).oTxtBx.Left = 100 aoTxtBxes(i).oTxtBx.Top = Me.Controls(«TextBox» & i — 4).Top Next i End Sub

Кратко описать, что делает эта процедура, можно так:

  1. при запуске формы в массив aoTxtBxes запоминаются сначала те ТекстБоксы, которые мы предусмотрительно заранее создали на форме
  2. затем создаются еще 4 новых ТекстБокса, которые также записываются в массив aoTxtBxes
  3. Т.к. массив aoTxtBxes у нас является новым экземпляром класса, то обращаться к его содержимому мы можем только по законам работы с классами, т.е. только к тем объектам и методам, которые в классе прописаны. А у нас там пока только один объект прописан — oTxtBx( Public WithEvents oTxtBx As MSForms.TextBox ). Его и используем. Ничего другого использовать VBE нам и не позволит
  4. т.к. класс мы создали, событие объекта прописали, объектам значения ТекстБоксов присвоили — остается только наслаждаться. Теперь любое изменение в любом из ТекстБоксов будет обработано и появится сообщение — «Вы изменили значение » + имя ТекстБокса

Если необходимо больше ТекстБоксов обработать — увеличиваем верхнюю границу массива aoTxtBxes(если хотим вместить 20 текстбоксов — Public aoTxtBxes(1 To 20) As New clsmTxtBxes ). Если заранее неизвестно количество — либо задаем с запасом, либо объявляем aoTxtBxes как динамический массив( Public aoTxtBxes() As New clsmTxtBxes ), а границы определяем в процессе(посредством ReDim Preserve ). Но это уже совершенно другая тема.

Конечно, здесь я привел лишь маленький пример показа сообщения при изменении ТекстБокса. Но ведь можно таким образом отследить практически любое доступное событие. И не просто сообщение показывать, а запретить ввод букв, делать проверку введенного значения на соответствие шаблону и пр. Все зависит от конкретной задачи.
Так же дополню, что подобным образом можно создавать и отслеживать и иные элементы форм. Для этого необходимо лишь изменить тип элемента здесь:

ПОЛЬЗОВАТЕЛЬСКИЕ ОБЪЕКТЫ

Создание модулей класса

В VBA наряду с огромным числом встроенных объектов предусмотрена возможность создания пользовательских объектов. Использование таких объектов позволяет сократить текст программы и сделать его более понятным. Пользовательские объекты являются элементами пользовательских классов (или образно говоря, классы являются формами, из которых «пекутся» конкретные объекты). Пользовательские классы конструируются в модулях классов, которые создаются в редакторе Visual Basic выбором команды Вставка, Модуль класса (Insert, Class Module). При создании классов надо предусмотреть его инициализацию, описание свойств и методов, которыми будет наделен объект.

Опишем процесс создания класса в виде следующей последовательности шагов:

  1. Выберите команду Вставка, Модуль класса (Insert, Class Module). Откроется окно нового модуля класса.
  2. Нажмите клавишу и присвойте в появившемся окне свойству Name имя класса. Имя модуля класса является именем класса объектов.
  3. В разделе описания модуля объявите переменные уровня модуля, которые используются как «значения свойств».
  4. Инициализируйте класс при помощи процедуры Private Sub Class_Initialize. В этой процедуре надо указать значения, принимаемые по умолчанию переменными уровня модуля, описывающими «значения свойств».
  5. При помощи процедур Property Let объявите имена свойств, значениями которых являются числовые данные, а при помощи процедур Property set объявите имена свойств, значениями которых являются объекты. Если какое-то свойство — только для чтения, то для него не надо составить процедуру Property Let.
  6. При помощи процедур Property Get установите возможность считывания значения свойств.
  7. Создайте методы класса. Методы создаются при помощи обычных процедур и функций. Если метод возвращает число, то для его конструирования используется функция, а в остальных случаях — процедура.
  8. Допустимо также создание процедуры Private Sub Class_Terminate для удаления объекта из памяти по завершению работы с ним.

Процедуры Property Let, Property Set и Property Get

Процедура Property Let служит для объявления имен свойств, значениями которых являются числовые данные.

Процедура Property set служит для объявления имен свойств, значениями которых являются объекты.

Процедура Property Get обеспечивает возможность считывания значения свойств.

Как видно из приведенного ниже синтаксиса, процедуры Property Let, Property Set и Property Get имеют такую же структуру, что и обычные процедуры. Просто, они предназначены для специфических задач, описанных выше.

[Public | Private] [Static] Property Let имя [(списокАргументов)]

[инструкции] End Property

Public | Private] [Static] Property Set имя.[(списокАргументов)]

[инструкции] End Property

[Public | Private] [Static] Property Get имя [(списокАргументов)] [As тип]

[инструкции] [имя = выражение] [Exit Property]

[инструкции] [имя = выражение] End Property

Пример создания класса

Рассмотрим пример создания класса Вектор, моделирующего двумерный вектор. У объектов класса вектор будут определены три свойства: координата абсциссы, координата ординаты и длина вектора (это свойство является свойством только для чтения). Кроме того, для объектов класса вектор будут определены два метода, первый из которых возвращает вектор, являющийся результатом покомпонентного произведения вектора на число, а второй — результат скалярного произведения двух векторов.

Итак, в модуле класса, у которого установлено свойство Name, равное Вектор, наберите следующий код:

Читать еще:  Offset vba excel описание

‘ X — координата абсциссы

‘ У — координата ординаты

Dim X, Y As Double

Public Property Get Абсцисса() As Double

‘ Возвращает значение свойства Абсцисса

Абсцисса = X End Property

Public Property Get Ордината () As Double

‘ Возвращает значение свойства Ордината

Public Property Let Абцисса(ByVal НоваяАбсцисса As Double)

‘ Устанавливает значение свойства Абсцисса

If Not IsNumeric(НоваяАбсцисса) Then

MsgBox «Абсцисса не является числом», vblnformation, «VBA»

Public Property Let Ордината(ByVal НоваяОрдината As Double)

‘ Устанавливает значение свойства Ордината

If Not IsNumeric(НоваяОрдината) Then

MsgBox «Ордината не является числом», vblnformation, «VBA»

Y = НоваяОрдината End Property

Public Property Get Длина() As Double

‘ Возвращает длину вектора. Это свойство только для чтения

Длина = Sqr(X ^ 2 + Y ^ 2)

Public Sub ПрибавитьВектор(ByVal ДругойВектор As Вектор)

‘ Покоординатное сложение двух векторов

X = X + ДругойВектор.Абсцисса Y = Y + ДругойВектор.Ордината

Public Sub УмножитьНаЧисло(ByVal Число As Double)

‘ Покоординатное умножение вектора на число

If Not IsNumeric(Число) Then

MsgBox «Число, на которое умножается вектор,» & Chr(13) & «на самом деле не число», vblnformation, «VBA»

X = Число * X Y = Число * У

Public Function СкалярноеПроизведение(ByVal ДругойВектор As Вектор)

‘ Скалярное произведение векторов

СкалярноеПроизведение = X * ДругойВектор.Абсцисса

Private Sub Class_Initialize()

Проверить работу созданного класса можно, например при помощи следующей процедуры, код которой набирается на стандартном листе модуля.

Dim a, s As Double

‘ Объявление двух векторов

Dim МойВектор, ЕщеВектор As Вектор

Set МойВектор = New Вектор

‘ Установка координат вектора

.Абсцисса = 1 .Ордината = 1

‘ Определение длины вектора

‘ Умножение вектора на 2

Определение координат преобразованного вектора

‘ Создание еще одного вектора

Set ЕщеВектор = New Вектор

.Ордината = 3 End With

‘ Определение координат преобразованного вектора

Неизменяемый класс объектов в VBA — Создается только через конструктор, а не через ключевое слово «Новое»

Цели для класса

  • Создать неизменяемые объекты — т. е. только Getters — no Setters
  • Создание объекта возможно только через конструктор, а не через ключевое слово New , чтобы гарантировать, что никакие объекты не создаются без допустимого состояния.
  • Храните метод конструктора в том же модуле кода, что и сам класс.

Другие общие решения для конструкторов VBA

Создание глобального Factory class /module, который предоставляет конструкторы для всех создаваемых объектов , как предложено в этот пост . Это может быть трудно поддерживать, создает зависимость между модулями и, возможно, нарушает принцип инкапсуляции /единой ответственности. Не позволяет использовать ключевое слово New для создания объектов.

Создание класса Factory для каждого класса Обеспечивает более инкапсуляцию, меньшую зависимость и более узкую ответственность, но опять же не предотвращает использование New и вскоре приводит к распространению типов.

Предоставление конструктора в самом классе и его доступность через предопределенный экземпляр с использованием атрибута VB_PredeclaredId, как описано в этот пост . Лучше, но все же разрешает использование ключевого слова New и не препятствует доступу к (потенциально недействительному) состоянию предварительно созданного экземпляра.

Предлагаемое решение

  • Используйте экземпляр класса preeclared как «Factory Instance». Только этот предварительно созданный экземпляр может создавать другие экземпляры класса.
  • Предоставить метод конструктора (я использую имя Make ) в самом модуле класса. Его можно вызвать в Factory Instance, используя ClassName.Make или в другом экземпляре класса, используя ObjectName.Make . Другие экземпляры делегируют создание в Factory Instance и возвращают новый объект — он не изменяет свое собственное состояние.
  • Каждый раз, когда инициализируется новый экземпляр, он проверяет, выполняется ли он с помощью Factory Instance, в противном случае возникает ошибка времени выполнения, то есть использование New не разрешено.
  • Попытка доступа к состоянию Factory Instance возвращает ошибку времени выполнения.

Реализация

Предоставляет интерфейс для объектов, запрашивающих Factory Instance, чтобы проверить, было ли запрошено их создание. Поместите отдельный интерфейс, чтобы он не отображался в публичных членах класса. Один и тот же интерфейс может использоваться всеми классами, использующими этот шаблон.

Point.cls — редактируется в блокноте, чтобы Attribute VB_PredeclaredId = True

Пример класса с двумя свойствами: X и Y. Подробные комментарии добавлены для иллюстративных целей

Недостатки

Это, очевидно, довольно «шаблонный» для простого объекта, но недостаток функций VBA, похоже, требует этого. Я бы приветствовал предложения по его оптимизации. Включение проверки в каждый метод, в котором объект не является экземпляром Factory, явно добавляет служебные данные и многословие, — может быть опущен, если вам неинтересно, что кодекс обращается к состоянию предварительно определенного экземпляра.

2 ответа

Отступ

Нестандартный отступ маркера в конце блока выключен; это первый раз, когда я вижу код VB, который не выравнивает столбцы начального и конечного токенов блоков кода:

Кажется, вы избегаете своего пути, чтобы бороться с IDE, чтобы последовательно применять этот стиль — я ценю последовательность, но мне становится неудобно, когда If. End If , похоже, не соответствуют тому же правилу — я бы ожидал этого:

Но у вас есть их стандартный способ, например:

Ваш отступы — это ваше личное предпочтение, конечно, но есть также общепринятые соглашения. Smart Indenter — это автоматическая надстройка для надстройки, которая существует почти для двух (переносится на .net и поддерживает хосты x64 через Rubberduck , проект с открытым исходным кодом, над которым я работаю — kudos @Comintern для работы с индентором); он предлагает TON отступов, и ни один из них не поддерживает этот стиль — я бы воспринял его как знак.

читаемость

Проверка состояния и проверка экземпляра работают, но для этого требуется внимательный читатель; назад и вперед между экземпляром по умолчанию и новым создаваемым объектом, назначением указателей Me , IsMaking . результат — довольно запутанный путь выполнения.

Он работает, , но это трудно понять.

IMaker

Интерфейс лишний; в то время как приятно, что вы формализуете состояние «Я делаю что-то», только вызовы IsMaking являются, как поясняет комментарий , сделанный из экземпляра по умолчанию того же класса, который реализует интерфейс, потому что ни один код не работает с экземпляром IMaker (и /или доступ к этому экземпляру из интерфейса IMaker ), интерфейс в конечном итоге бесполезен.

Обработка ошибок

Мне нравится то, что я вижу: частные процедуры, предназначенные для повышения определенных ошибок времени выполнения. Константа CLASS_NAME может быть легко устранена при вызове TypeName(Me) .

Однако у вызывающего кода нет простого способа сообщить VBA.vbObjectError + 513 из VBA.vbObjectError + 514 без жесткого кодирования этих магических значений; класс может открыть для него общедоступный список:

Таким образом вы можете поднять их, не прибегая к магическим номерам:

Обратите внимание, что это сообщение очень похоже на ошибку времени компиляции Недопустимое использование ключевого слова« Новое » ; Я бы предположил, что сообщение об ошибке аналогично.

И теперь вызывающие могут справиться с этой ошибкой, также не прибегая к магическим номерам:

. который кажется довольно странным, учитывая, что ошибка во время выполнения должна быть действительно ошибкой времени компиляции, а это означает, что ошибка будет возникать только в случае ошибки, введенной программистом.

Возможно,
—- +: = 17 =: + —- звонки станут лучшей альтернативой:

Неизменность

В VB6 вы должны установить атрибут Debug.Assert Not Me Is Point ‘breaks on-the-spot if assertion fails в VB_Creatable , и у вас был класс, который вы не могли бы False вверх, но пока этот атрибут появляется в экспортированном модуле класса, он не имеет никакого эффекта в VBA .

Мне нравится, как ваш класс знает свой экземпляр по умолчанию и использует это знание, чтобы запретить доступ к состоянию этого экземпляра. Это немного смехотворно, но если вы работаете в проекте VBA без других ссылок на проект VBA, это почти единственный путь.

Классы VBA могут быть только New ‘d в рамках проекта, в котором они находятся. Это означает, что вы получаете New , если вы ставите такие неизменные типы в свой собственный проект VBA проекта.

Если наличие проекта «framework /toolbox add-in» является опцией (неизменный тип Attribute VB_Creatable = False кажется довольно полезным типом для иметь в своем наборе инструментов), то есть еще одно, гораздо более простое решение: модификаторы доступа .

Читать еще:  Ubound vba excel

Модификатор Point означает, что член может быть доступен только из проекта, в котором он находится. Это означает, что вы можете очень хорошо это сделать:

И тогда любой проект VBA, который использует этот тип, никогда не узнает о члене Public Property Get X() As Double X = X_ End Property Friend Property Let X(ByVal value As Double) X_ = value End Property . В сочетании с тем, что класс не может быть Property Let ‘d, потому что он объявлен в другом проекте, на который ссылается, результат фактически является неизменным экземпляр.

Вы также можете заставить клиентский код работать с интерфейсом для типа — скажем New :

И затем вы используете экземпляр по умолчанию Option Explicit Public Property Get X() As Double End Property Public Property Get Y() As Double End Property в качестве фабрики для Point — вот как бы я это сделал:

Частный тип Private Type TPoint X As Double Y As Double End Type Private this As TPoint Implements IPoint Public Function Create(ByVal X As Double, ByVal Y As Double) As IPoint With New Point .X = X .Y = Y Set Create = .Self End With End Function Friend Property Get Self() As Point Set Self = Me End Property Friend Property Let X(ByVal value As Double) this.X = value End Property Friend Property Let Y(ByVal value As Double) this.Y = value End Property Private Property Get IPoint_X() As Double IPoint_X = this.X End Property Private Property Get IPoint_Y() As Double IPoint_Y = this.Y End Property позволяет мне иметь поля поддержки с тем же именем, что и свойство, которое их предоставляет, без каких-либо фанковых префиксов или суффикс — и все вызовы полей поддержки все еще очевидны, потому что они являются всеми вызовами доступа к частному полю TPoint , которое ответственный за сохранение инкапсулированного состояния экземпляра.

И если вам когда-нибудь понадобится сериализовать экземпляр this , вы всегда можете получить их, если тип реализует некоторый Point :

Из вызывающего кода (в другом проекте VBA) членами класса Private Property Get ISerializable_Size() As Long ISerializable_Size = LenB(this) End Property Private Sub ISerializable_Serialize(ByVal fileNumber As Long) Put# fileNumber, this End Sub Private Function ISerializable_Deserialize(ByVal fileNumber As Long) As Object Dim value As TPoint Get# fileNumber, value Set ISerializable_Deserialize = Create(value.X, value.Y) End Sub являются:

. и это абсолютно все.

Чтобы получить доступ к состоянию экземпляра, вызывающий код должен работать с интерфейсом Public Function Create(ByVal X As Double, ByVal Y As Double) As IPoint :

. который предоставляет только Dim p As IPoint Set p = Point.Create(42, 17) для Property Get и X : API такой же чистый, как и он, и в качестве бонуса вы получите это бесплатно: /р>

Конечно, если тип должен быть определен в том же проекте VBA, который его потребляет, тогда все становится грязнее, потому что VBA позволит вам Dim p As Point Set p = New Point ‘compile error , и у вас есть доступ к членам экземпляра по умолчанию New , поэтому вы можете захотеть добавьте проверки экземпляра, чтобы явно запретить это . как и вы; но даже если он потребляется в одном проекте, вызывающий код должен всегда работать с интерфейсом Friend , поэтому состояние экземпляра по умолчанию никогда не будет все равно.

РЕДАКТИРОВАТЬ Mat’s Mug имеет лучший подход при работе с интерфейсом и надстройкой, но если вы ограничите требования к автономному решению и предположите, что пользователь этого класса незнаком с интерфейсами, тогда вы можете иметь все в одном классе.

Ваш экземпляр с предустановленным именем имеет частные поля и свойство получает возможность передавать переменные в новые экземпляры. Я добавил свойство State (заменив ваш IsMaking ) с областью Friend (если класс окажется в надстройке), и я использовал способность VBA чтобы скрыть элемент emum путем префикса его подчеркиванием, чтобы обфускать значения, которые в противном случае могли бы быть State (т. е. потребители класса don ‘ t знать, что делает State , и только знать, что State может быть Ready .

Настройка некоторых перечислений

Как отметил @ Mat’sMug, значения ошибок могут использовать собственный Enum:

И, я буду использовать Enum для установки состояния экземпляра preeclareed. Он либо готов, либо инициализирует новый пункт. Обратите внимание на использование ведущего кода _ , чтобы сделать скрытый элемент перечисления, отличного от значения по умолчанию, и использование квадратных скобок, чтобы сделать синтаксис действительным .

Создание полей более дружелюбным

Затем, опять же по предложению Мат’Муга, я использую закрытый тип для хранения полей:

Удержание захваченных полей экземпляра

В заводском методе Create , я временно устанавливаю состояние и поля X /Y по умолчанию экземпляр, а затем в событии Class_Initialize экземпляра new , я читаю эти поля, хотя получатели экземпляра по умолчанию , Таким образом, я смягчил условия, связанные с возможностью доступа к получателям экземпляра по умолчанию, но это можно было легко добавить. Значение по умолчанию Point всегда будет возвращать хэтчи X и Y 0, во многом таким же образом, что по умолчанию Integer всегда будет иметь значение по умолчанию 0.

Полный код

Это предварительно объявленный класс. Я требую, чтобы из экземпляра по умолчанию создавались новые экземпляры Point и only экземпляр по умолчанию для Point (это означает, что экземпляр по умолчанию мог бы делать полезные вещи, такие как отслеживание количества экземпляров Point), но это не так много, чтобы облегчить любой экземпляр Point, являющийся допустимым фабрикой.

VBA Excel. Объект Collection (создание, методы, примеры)

Создание объекта Collection с помощью кода VBA Excel. Методы коллекции и синтаксис выражений с ними. Свойство Count и примеры кода.

Создание объекта Collection

Создать новый экземпляр Collection в коде VBA Excel можно двумя строками:

или одной строкой:

Лист автоматической вставки объектов, методов и свойств (лист подсказок) предоставит при написании кода VBA Excel простой доступ к методам Add, Item, Remove и свойству Count объекта Collection:

Лист подсказок отображается автоматически после ввода точки или, в иных случаях, вызывается сочетанием клавиш «Ctrl+Пробел».

Методы и свойство коллекции

Метод Add

Метод Add добавляет новый элемент в объект Collection.

Синтаксис метода Add:

Компоненты метода Add:

  1. Collection – обязательный компонент, представляющий выражение (переменную), возвращающее объект Collection.
  2. Элемент – обязательный аргумент, представляющий выражение любого типа, возвращающее элемент, который необходимо добавить в коллекцию.
  3. Ключ – необязательный аргумент, представляющий строковое выражение, задающее уникальный ключ, который может использоваться вместо индекса позиции для доступа к элементу коллекции.
  4. До* – необязательный аргумент, указывающий на позицию существующего элемента в коллекции, перед которым будет добавлен новый элемент.
  5. После* – необязательный аргумент, указывающий на позицию существующего элемента в коллекции, после которого будет добавлен новый элемент.

* Аргументы «До» и «После» не могут применяться одновременно. Если аргументу «До» или «После» присвоено числовое значение, оно должно быть в пределах диапазона от 1 до значения свойства Collection.Count. Если это строка, она должна соответствовать одному из ключей существующих в коллекции элементов.

Метод Item

Метод Item возвращает элемент объекта Collection по индексу позиции или по ключу.

Синтаксис метода Item объекта Collection:

Компоненты метода Item:

  • Collection – обязательный компонент, представляющий выражение (переменную), возвращающее объект Collection.
  • Index – обязательный аргумент, представляющий выражение, возвращающее номер (индекс) позиции элемента коллекции или его уникальный ключ.

Метод Remove

Метод Remove удаляет элемент из объекта Collection по индексу позиции или по ключу.

Синтаксис метода Remove объекта Collection:

Компоненты метода Remove:

  • Collection – обязательный компонент, представляющий выражение (переменную), возвращающее объект Collection.
  • Index – обязательный аргумент, представляющий выражение, возвращающее номер (индекс) позиции элемента коллекции или его уникальный ключ.

Свойство Collection.Count

Свойство Count объекта Collection возвращает количество элементов в коллекции.

Примеры кода с объектом Collection

Пример 1
Создание нового экземпляра объекта Collection, добавление в коллекцию трех элементов, определение количества элементов в коллекции, извлечение одного и того же элемента по индексу и по ключу:

Ссылка на основную публикацию
ВсеИнструменты
Adblock
detector
×
×