Juri Shutenko Personal Homepage. Visual FoxPro.

Коллекции - как много в этом слове!

Наверное каждый из читающих эту статью что-то коллекционирует или коллекционировал ранее, начиная с фантиков от конфет до автомобилей мировых звезд. Каждому свое. Коллекционирование не чуждо и Лису, (коллекции Controls в формах, Files в активном проекте и т.п.). К зрелости, а точнее к восьмой версии, Лис собрался и начал коллекционировать посредством отдельного класса, причем все подряд, что придет в голову программисту, тренирующего рыжего хищника.

Итак, с восьмой версии, программисту предоставлен новый класс - collection - коллекции. Класс, который не богат свойствами и методами, да и те не все представляют интерес для программиста. Что мы имеем?

Свойства(представляющие интерес для нас выделены красным):

  1. BaseClass
  2. Class
  3. ClassLibrary
  4. Comment
  5. Count
  6. KeySort
  7. Name
  8. Parent
  9. ParentClass
  10. Tag

... методы (представляющие интерес для нас выделены красным):

  1. Add
  2. AddProperty
  3. GetKey
  4. Item
  5. ReadExpression
  6. ReadMethod
  7. Remove
  8. ResetToDefault
  9. SaveAsClass
  10. WriteExpression
  11. WriteMethod

... и события:

  1. Destroy
  2. Error
  3. Init

Почитаем, что говорится о коллекциях в руководстве по языку.

Вы можете использовать коллекции для группировки связанных предметов, в качестве которых обычно выступают объекты, которые, в свою очередь, могут быть любого типа. Коллекции предоставляют механизм для работы с объектами, хранящимися в контейнерах и включают в себя стандартные пути доступа и прохода по объектам коллекции. Класс Collection работает как истинный контейнерный класс, несмотря на то, что среди его методов отсутствует AddObject, обычный, к примеру, для классов форм и страничных фреймов.
 
Класс Collection представляет собой базовый класс, который вы можете субклассировать в файлах программ и библиотек классов
.

цитирую еще раз "среди его методов отсутствует AddObject". Ох, уж это руководство. После такой фразы невольно возникает вопрос - а как заполнить коллекцию? Нет чтобы написать: "класс Collection работает как истинный контейнерный класс, в котором для заполнения коллекции объектами используется метод Add, отличающийся по поведению от традиционного метода AddObject, обычного, к примеру, для классов форм и страничных фреймов".

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

Создать коллекцию так же просто, как и любой другой класс. Напечатаем в командном окне приведенную ниже строку:

oCollection=CREATEOBJECT("Collection")

Что можно добавить в коллекцию? Как сказано в руководстве - "объект - член коллекции - может быть любого действительного типа, который можно присвоить переменной памяти. Это включает в себя простые типы данных, такие как строки, числа, даты, логические значения (интересно, а какой смысл вводить в коллекцию логические значения? Правда это можно использовать достаточно своеобразно, но об этом позже) или более сложные типы, так как объекты Visual FoxPro и объекты Component Object Model (COM).

Добавим две строки в наш объект. Для этого необходимо использовать метод Add, чей синтаксис прост и содержит три параметра:

Collection.Add( eItem [, cKey [, [eBefore |, eAfter ]]] )

Я специально выделил второй параметр красным цветом. Объект - член коллекции - может иметь ключ. Но! Либо вы используете ключи со всеми вводимым в коллекцию объектами, либо ни с одним из них!

Итак исполним предложенное:

oCollection.Add( "String that I suffer out before lunch","String1")
oCollection.Add( "String that I wrote with a great trouble after lunch","String2")

Поскольку ключи могут быть использованы для обращения к объекту-члену коллекции, то стало быть они должны быть уникальными. Если вы попытаетесь использовать в качестве ключа выражение, уже имеющееся в коллекции, то вы неизбежно получите сообщение об ошибке Error 2062 - The specified Key already exists (Указанный ключ уже существует)

Коллекция создана и в ней хранится два объекта - две строки. Как к ним обратиться? Очень просто! Можно использовать введенные одновременно с объектом ключи, а можно использовать целочисленный индекс, автоматически создающийся при вводе объекта в коллекцию. То есть, два приведенных ниже выражения равнозначны по сути.

? oCollection.Item("String1")
? oCollection.Item(1)

Как удалить объект из коллекции? Также очень просто! Если нужно удалить конкретный объект, то в методе Remove указываем либо его ключ, либо его индекс. Если же мы хотим очистить всю коллекцию одним махом - то нужно вызвать метод Remove, которому в качестве параметра передать -1 (минус единицу)

? oCollection.Remove("String1") 
? oCollection.Remove("String2")
? oCollection.Count

Последняя строка вернет ноль - 0. А что произойдет, если мы воспользуется третьим параметром. Поскольку наша тестовая коллекция в данный момент пуста, заполним ее следующим образом:

oCollection.Add(1,"N1")
oCollection.Add(2,"N2")
oCollection.Add(3,"N3","N1")
oCollection.Add(4,"N4",,"N1")

Что мы сделали? Первая и вторая строки кода добавляют два числа в коллекцию, третья строка кода вставляет объект, имеющий ключ "N3" в коллекцию перед объектом-членом коллекции, чей ключ имеет выражение "N1", а четвертая строка вставляет объект, имеющий ключ "N4" после объекта-члена коллекции "N1", что сделано с помощью двух запятых в синтаксисе вызова метода. Посмотрим теперь содержание коллекции, используя целочисленные индексы:

? oCollection.Item(1)
? oCollection.Item(2)
? oCollection.Item(3)
? oCollection.Item(4)

В результате мы получим значения 3,1,4,2. То есть при вводе с использованием опции eBefore | eAfter индексы коллекции перестраиваются, что необходимо учитывать, при их использовании. Но спасательная веревка все-таки существует, поскольку у класса коллекции имеется метод GetKey, который может быть использован для проверки - а к нужному ли объекту мы обращаемся. Однако, метод будет работать только при наличии введенных для каждого объекта-члена коллекции ключей.

Естественно возникает вопрос - а можно ли использовать третий параметр, в случае, если не используются ключи? Что написано по этому поводу в руководстве? "Inserting a new item into a collection before or after an existing one requires that the collection must be a keyed collection" - Вставка нового объекта в коллекцию до или после существующего объекта-члена коллекции требует, чтобы коллекция была создана с использованием ключей. Так ли это? Попробуем вставить объекты в коллекцию с использованием третьего параметра метода Add, предполагая, что в его качестве будут использованы индексы:

* очистим объект коллекции, созданный в предыдущем примере
oCollection.Remove(-1)
oCollection.Add(1)
oCollection.Add(2)
oCollection.Add(3,,1)
oCollection.Add(4,,,1)
? oCollection.Item(1)
? oCollection.Item(2)
? oCollection.Item(3)
? oCollection.Item(4)

Итак, что мы сделали. Для начала мы удалили из коллекции все объекты-члены. Следующие две строки добавили два члена коллекции, которым автоматически были присвоены индексы 1 и 2 соответственно. Третья строка должна ввести объект в коллекцию перед объектом-членом коллекции, чей индекс равен 1. И четвертая строка должна ввести объект в коллекцию после объекта-члена коллекции, чей индекс равен 1. В итоге мы получили 3,4,1,2. Получается, что использование индексов вместо ключей, возможно. Однако, приведенный пример имел одну неопределенность, которая состояла в том, что в качестве объектов использовались целые числа, того же порядка, что и индексы. Проверим, использовались ли индексы коллекции при вызове метода Add, если в качестве объектов вводились символьные значения. Для этого исполним приведенный ниже пример:

oCollection.Remove(-1)
oCollection.Add("A")
oCollection.Add("B")
oCollection.Add("C",,1)
oCollection.Add("D",,,1)
? oCollection.Item(1)
? oCollection.Item(2)
? oCollection.Item(3)
? oCollection.Item(4)

В итоге мы получим в качестве результата C,D,A,B, что подтверждает предположение о возможности использовании индексов в качестве третьего параметра метода Add. Ну хорошо, а что если использовать в качестве третьего параметра ссылку на объект коллекции?. То есть oCollection.Item(n)? Вызов метода возвращает непосредственно объект-член коллекции. Стало быть в чистом виде мы его не можем использовать для организации коллекции с указанием места вставки нового объекта. Хотя это вполне реально сделать в субклассе коллекции, основаном на базовом классе коллекции Visual FoxPro. Но об этом в одной из следующих частей.

Cелектор для быстрого перехода на сайты, связанные с Visual FoxPro.