класс 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'.