Иллюстрированный самоучитель по VB.NET

       

класс CollectionBase


При использовании классов коллекций .NET Framework (таких, как ArrayList и HashTable) возникает неожиданная проблема: эти классы предназначены для хранения обобщенного типа Object, поэтому прочитанные из них объекты всегда приходится преобразовывать к исходному типу функцией СТуре. Также возникает опасность того, что кто-нибудь сохранит в контейнере объект другого типа и попытка вызова СТуре завершится неудачей. Проблема решается использованием коллекций с сильной типизацией — контейнеров, позволяющих хранить объекты конкретного типа и типов, производных от него.

Хорошим примером абстрактного базового класса .NET Framework является класс CollectionBase. Классы, производные от Coll ectionBase, используются для построения коллекций с сильной типизацией (прежде чем создавать собственные классы коллекций, производные от Coll ectionBase, убедитесь в том, что нужные классы отсутствуют в пространстве имен System.Collections.Specialized). Коллекции, безопасные по отношению к типам, строятся на основе абстрактного базового класса System. Collections. CollectionBase; от вас лишь требуется реализовать методы Add и Remove, а также свойство Item. Хранение данных во внутреннем списке реализовано на уровне класса System. Collections. CollectionBase, который и выполняет все остальные операции.

Рассмотрим пример создания специализированных коллекций (предполагается, что проект содержит класс Employee или ссылку на него):

1 Public Class Employees

2 Inherits System.Col lections.CollectionBase

3 ' Метод Add включает в коллекцию только объекты класса Employee.

4 ' Вызов перепоручается методу Add внутреннего объекта List.

5 Public Sub AddtByVal aEmployee As Employee)

6 List.Add(aEmployee)

7 End Sub

8 Public Sub Remove(ByVal index As Integer)

9 If index > Count-1 Or index < 0 Then

10 ' Индекс за границами интервала, инициировать исключение (глава 7)



11 MsgBox("Can't add this item")' MsgBox условно заменяет исключение

12 Else

13 List.RemoveAt(index)



14 End If

15 End Sub

16

17 Default Public Readonly Property Item(ByVal index As Integer)As Employee

18 Get

19 Return CType(List.Item(index). Employee)

20 End Get

21 End Property

22 End Class

В строках 5-7 абстрактный метод Add базового класса реализуется передачей вызова внутреннему объекту List; метод принимает для включения в коллекцию только объекты Empl oyee. В строках 8-10 реализован метод Remove. На этот раз мы также используем свойство Count внутреннего объекта List, чтобы убедиться в том, что удаляемый объект не находится перед началом или после конца списка. Наконец, свойство Item реализуется в строках 17-21. Оно объявляется свойством по умолчанию, поскольку пользователи обычно ожидают от коллекций именно такого поведения. Свойство объявляется доступным только для чтения, чтобы добавление новых элементов в коллекцию могло осуществляться только методом Add. Конечно, свойство можно было объявить и доступным для чтения/записи, но тогда потребовался бы дополнительный код для проверки индекса добавляемого элемента. Следующий фрагмент проверяет работу специализированной коллекции; недопустимая операция включения нового элемента (в строке, выделенной жирным шрифтом) закомментирована:

Sub Main()

Dim torn As New Employee("Tom", 50000)

Dim sally As New Employee("Sally", 60000)

Dim myEmployees As New Employees()

myEmployees.Add(tom)

myEmployees.Add(sally)

' myEmployees.Add("Tom")

Dim aEmployee As Employee

For Each aEmployee In myEmployees

Console.WriteLine(aEmployee.TheName)

Next

Console. ReadLine()
End Sub

Попробуйте убрать комментарий из строки myEmpl oyees. Add("Tom"). Программа перестанет компилироваться, и вы получите следующее сообщение об ошибке:

C:\book to comp \chapter 5\EmployeesClass\EmployeesClass\Modulel.vb(9):
A value of type 'String'cannot be converted to 'EmployeesClass.Employee'.

Перед вами замечательный пример того, какими преимуществами VB .NET обладает перед включением в прежних версиях VB.Конечно, мы продолжаем перепоручать вызовы внутреннему объекту, чтобы избавиться от дополнительной работы, но возможность перебора элементов в цикле For-Each появляется автоматически, поскольку наш класс является производным от класса с поддержкой For-Each!

Содержание раздела