MyTetra Share
Делитесь знаниями!
Работа с коллекциями классов
Время создания: 29.07.2019 16:35
Раздел: !Закладки - VBA - Меню VB-справка
Запись: xintrea/mytetra_db_adgaver_new/master/base/1514300161otuldg4kxw/text.html на raw.githubusercontent.com

Работа с коллекциями классов

     Одна из самых замечательных идей (правил) в объектно-ориентированном программировании является абстрагирование. При соблюдении этого правила, мы отдаляемся от кода и работаем с объектами, их свойствами, методами, как будто они существуют в нашем, физическом мире. Главное, что отличает класс от процедуры – возможность одновременного запуска нескольких экземпляров класса. Например, на основе класса «Cat» (Кот) можно создать несколько объектов и задать различные значения свойствам «Name» (Имя) и «Color» (Окраска). Для простой демонстрации создадим класс Cat с перечисленными ранее свойствами: Код класса:

Option Explicit

Private NValue As String

Private CValue As String

 

Property Let Name(NameValue As String)

 NValue = NameValue

End Property

 

Property Get Name() As String

 Name = NValue

End Property

 

Property Let Color(ColorValue As String)

 CValue = ColorValue

End Property

 

Property Get Color() As String

 Color = CValue

 End Property

      Код вызова класса в модуле:

Sub TestCat()

 Dim Kity As Cat

 Set Kity = New Cat

 Kity.Color = "Рыжий"

 Kity.Name = "Барсик"

 Debug.Print Kity.Color, Kity.Name

End Sub

В примере выше создан объект Kity на основе класса Cat. Свойствам объекта задали значения. Создадим массив объектов на основе класса Cat (стаю котов):

Sub ManyCats()

 Dim Cats(1 To 3) As Cat’объявляем массив типа Cat

 Dim i As Integer

 For i = 1 To 3

 Set Cats(i) = New Cat’создаем объект и присваиваем значению массива

 Next i

 Cats(1).Color = "Белый"’задаем значения свойства

 Cats(2).Color = "Рыжий"

 Cats(3).Color = "Серый"

 For i = 1 To 3

 Debug.Print Cats(i).Color’читаем свойство

 Next i

End Sub

      Никто не запрещает создать многомерный массив… Все отлично. Мы создали стаю котов из 3 штук, читаем и задаем их свойства по индексу массива. Но чтобы добавить еще одного кота, необходимо переобъявлять массив, а для удаления кота присвоить значение Nothing. Добавление объекта в массив будет выглядеть так:

Dim Cats() As Cat 'обратите внимание, объявляем массив без размера

 Dim i As Integer

 ReDim Cats(1 To 3) As Cat 'меняем размер первый раз

 For i = 1 To 3

 Set Cats(i) = New Cat 'заполняем

 Next i

 Cats(1).Color = "Рыжий" 'задаем свойства

 Cats(2).Color = "Серый"

 Cats(3).Color = "Белый"

 ReDim Preserve Cats(1 To 4) As Cat 'меняем размер второй раз

 Set Cats(4) = New Cat 'заполняем

 Cats(4).Color = "Дымчатый" 'задаем свойства

 For i = 1 To 4

 Debug.Print Cats(i).Color 'читаем

 Next i

      А при удалении объекта из массива нужно быть осторожным:

 Dim Cats(1 To 3) As Cat 'объявляем массив

 Dim i As Integer

 For i = 1 To 3

 Set Cats(i) = New Cat 'заполняем

 Next i

 Cats(1).Color = "Рыжий" 'задаем свойства

 Cats(2).Color = "Серый"

 Cats(3).Color = "Белый"

 Set Cats(2) = Nothing 'удаляем объект из массива

 Debug.Print Cats(1).Color 'читаем по отдельности

 ' Debug.Print Cats(2).Color потому что здесь будет ошибка. Объекта нет...

 Debug.Print Cats(3).Color

      В данном случае мы не изменяем размерность массива, просто присваиваем объекту значение Nothing. Если нужно пройти по всем объектам массива и прочитать их свойства, можно воспользоваться циклом For Each…Next.

Dim Cats(1 To 3) As Cat 'объявляем массив

 Dim i As Integer

 For i = 1 To 3

 Set Cats(i) = New Cat 'заполняем

 Next i

 Cats(1).Color = "Рыжий" 'задаем свойства

 Cats(2).Color = "Серый"

 Cats(3).Color = "Белый"

 Dim c As Variant 'объявляем переменную как вариант (как cat не пройдет)

 For Each c In Cats 'проходим по массиву

 Debug.Print c.Color 'читаем свойство

 Next c

      Однако не следует забывать, что переменная, с помощью которой проходим по массиву должна иметь тип Variant. Хороший способ использования нескольких одинаковых объектов, это объединить их в коллекцию. Коллекция это объект, построенный на основе класса Collection, предназначенный для хранения данных (в том числе и других объектов). Он очень похож на одномерный массив. Индекс коллекции всегда начинается с 1. Свойства объекта Collection: Count – содержит число элементов (Item) коллекции. Item(index) – возвращает значение элемента (объект) по его индексу. Свойство также может вернуть значение по ключу. Об этом ниже… Методы: Add(Item, [Key], [Before], [After]) – Добавляет элемент в коллекцию. Параметр Item должен содержать добавляемое значение или объект. Это обязательный параметр. Остальные параметры не являются обязательными: Key – строковый ключ для элемента. Он должен быть уникальным. After и Before – выражение, указывающее перед каким или после какого элемента вставить новый. Если параметры числовые, они могут принимать значения от 1 до Count и вставка пройдет по индексу элементов, если параметры строковые, они должны содержать существующие названия ключей, и вставка будет происходить по ключам. Нельзя указывать два этих параметра сразу, только по отдельности. Ну как тут не вспомнить о коллекции Sheets… Вот пример создания коллекции и добавление элементов:

 Dim i As Integer

 Dim Cats As Collection 'объявляем коллекцию

 Set Cats = New Collection 'создаем коллекцию

 For i = 1 To 3

 Cats.Add Item:=New Cat, Key:="Cat_" & i 'добавляем в коллекцию объекты

 Next i

 

 Cats(1).Color = "Рыжий" 'задаем свойства

 Cats(2).Color = "Белый"

 Cats(3).Color = "Черный"

 

 Debug.Print Cats.Item("Cat_1").Color 'читаем свойства

 Debug.Print Cats.Item(2).Color

 Debug.Print Cats("Cat_1").Color

 

 Dim c As Cat 'еще способ читать свойства

 For Each c In Cats

 Debug.Print c.Color

 Next c

      Очень интересная вещь: при использовании конструкции For Each…Next, переменная c объявлена как Cat, а это означает ,что при написании кода, нам доступен просмотр свойств и методов класса cat. Это удобно. Вот пример удаления объекта из коллекции:

Dim i As Integer

 Dim Cats As Collection 'объявляем коллекцию

 Set Cats = New Collection 'создаем коллекцию

 For i = 1 To 3

 Cats.Add Item:=New Cat, Key:="Cat_" & i 'добавляем в коллекцию объекты

 Next i

 

 Cats(1).Color = "Рыжий" 'задаем свойства

 Cats(2).Color = "Белый"

 Cats(3).Color = "Черный"

 

 Cats.Remove 2 'Удаляем второй объект из коллекции

 ' Cats.Remove ("Cat_2") 'по ключу удалять так же можно

 Dim c As Cat 'еще способ читать свойства

 For Each c In Cats

 Debug.Print c.Color

 Next c

 Debug.Print Cats("Cat_3").Color 'число объектов изменилось и обращаться к ним лучше по ключам

      При удалении объектов из коллекции меняется свойство Count. В работе с коллекциями мне больше всего нравиться использование ключей.

Dim i As Integer

 Dim c As Cat

 Dim Cats As Collection 'объявляем коллекцию

 Set Cats = New Collection 'создаем коллекцию

 Set c = New Cat

 c.Name = "Барсик"

 Cats.Add Item:=c, Key:=c.Name 'добавляем в коллекцию объекты

 Set c = New Cat

 c.Name = "Дымок"

 Cats.Add Item:=c, Key:=c.Name

 Set c = New Cat

 c.Name = "Ушлепок"

 Cats.Add Item:=c, Key:=c.Name

 

 Cats("Дымок").Color = "Дымчатый" 'обращаемся к элементу коллекции по ключу

 Debug.Print Cats("Дымок").Color

      То есть даже, если число элементов изменится, всегда можно достучаться до нужного элемента по его ключу. Создание класса со свойством, содержащим коллекцию В файле csvDataLoader.zip предложено практическое применение вышеописанной теории с котиками. Только вместо котиков ячейки. Некоторые программы создают в результате своей деятельности файлы *.csv, которые содержат строки, в которых данные разделены запятыми. Я не нашел способа доступа к данным по номеру строки и столбца в vba, пришлось сделать самому. В примере создано подобие объектной модели для таких файлов, то есть адаптер для доступа к данным. Можно получать доступ к данным по номеру строки и столбца. Более того, в объектную модель можно загрузить несколько файлов и доступ будет осуществляться по имени файла (индексу), номеру строки и столбца. То есть получается фактически аналог книги Excel. Конечно, пример только учебный, в нем нет обработки ошибок, проверки многих исключений, не реализован поиск. Хорошо бы реализовать запись данных по индексам. Но пример этот хорошо демонстрирует способы работы с коллекциями и массивами объектов, построенных на основе собственных классов. Так же демонстрирует способ разработки внятной объектной модели, которая не реализована в Excel изначально. Подобные адаптеры для доступа к данным можно создать для любых типов файлов, в том числе и для пользовательских бинарных форматов, особенно, если планируется часто работать с ними. Кстати вот поиск для нашего адаптера:

Public Function SearchFirstCell(Data As String, Optional Column As Long = 0) As Cell

 Dim r As Long

 Dim c As Long

 Dim cl As Cell

 Select Case Column

 Case 0

 For r = 1 To UBound(DataArray, 1)

 For c = 1 To UBound(DataArray, 2)

 If DataArray(r, c).Value = Data Then

 Set SearchFirstCell = DataArray(r, c)

 Exit Function

 End If

 Next c

 Next r

 Case Else

 For r = 1 To UBound(DataArray, 1)

 If DataArray(r, Column).Value = Data Then

 Set SearchFirstCell = DataArray(r, Column)

 Exit Function

 End If

 Next r

 End Select

 Set cl = New Cell

 cl.Value = "Указанное значение не найдено"

 Set SearchFirstCell = cl

 End Function

      Метод осуществляет точный поиск первой ячейки. Требует указания искомого значения. Параметр столбец является необязательным. При его указании поиск осуществляется только по указанному столбцу. Метод возвращает объект. Пример использования:

Debug.print DataReader. SearchFirstCell("202”).Row

      Найдет ячейку, содержащую значение 202 и вернет ее номер строки. 

Желаю успехов в разработке
ratboy
ondister@gmail.com

 

Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования