ICollection

Интерфейс ICollection определяется производным от IEnumerable; он дополняет этот интерфейс тремя свойствами, доступными только для чтения, и одним новым методом. Класс ICollection редко реализуется самостоятельно. Как правило, он образует базу для интерфейсов IList и IDictionary (см. ниже). Члены этого интерфейса перечислены в табл. 5.2.

Таблица 5.2. Члены интерфейса ICollection

Метод/свойство

Описание

Count (свойство) Возвращает количество элементов в коллекции
IsSynchronized (свойство) Используется в многопоточных приложениях (см. главу 12). Свойство возвращает True, если доступ к коллекции синхронизируется с учетом многопоточного доступа
SyncRoot (свойство) Также используется в многопоточных приложениях (см. главу 12). Свойство возвращает объект для синхронизации доступа к коллекции
СоруТо (метод) Копирует элементы из коллекции в массив, начиная с заданной позиции

 

Интерфейс ICollection реализуется классом System.Collections.CollectionBase.

 

IList

Интерфейс IList обеспечивает выборку элементов коллекции по индексу. Разумеется, поскольку этот интерфейс определяется производным от I Enumerable, при этом сохраняется возможность использования For-Each. Иерархия наследования IList выглядит следующим образом:

IEnumerable->ICollection->IList

Интерфейс IList относительно сложен — он состоит из трех свойств и семи методов (табл. 5.3). Напомним, что некоторые из методов могут быть пустыми, если в каком-то конкретном классе их реализация не имеет смысла.

Таблица 5.3. Члены интерфейса IList

Метод/свойство

Описание

IsFixedSize (свойство) Логическое свойство. Показывает, имеет ли коллекция фиксированный размер
IsReadOnly (свойство) Логическое свойство. Показывает, доступна ли коллекция только для чтения
Item (свойство) Свойство доступно для чтения и записи. Используется для получения и присваивания значения объекта с заданным индексом
Add (ByVal value As Object) As Integer (метод)

Включает объект в текущую позицию списка. Метод должен возвращать индекс, присвоенный добавленному элементу

Clear (метод)

Удаляет все элементы из списка

Contains (ByVal value As Object) As Boolean (метод)

Метод предназначен для проверки наличия в списке заданного значения. Эффективная реализация этого метода иногда бывает весьма нетривиальной задачей. Если элемент присутствует в списке, метод возвращает True; в противном случае возвращается False

IndexOf (ByVal value As Object) As Integer (метод)

Возвращает индекс заданного объекта в списке (программист также должен учитывать эффективность реализации этого метода)

Insert(ByVal index As Integer, ByVal value As Object) (метод)

Вставляет объект в заданную позицию списка

Remove(ByVal value As Object) (метод)

Удаляет первое вхождение заданного объекта в списке

Remove(ByVal index As Integer) (метод)

Удаляет элемент, находящийся в заданной позиции

 

Интерфейс IList реализуется классом System.Collections.CollectionBase.

 

IDictionary

Интерфейс IDictionary представляет коллекцию, в которой доступ к данным осуществляется по ключу — как в хэш-таблицах, описанных в предыдущей главе. Более того, класс хэш-таблиц в числе прочих реализует интерфейсы IDictionary, ICollection, Enumerable и ICloneable!

Хотя интерфейс IDictionary объявляется производным от Enumerable и переход к следующему элементу может осуществляться методом MoveNext, обычно такая возможность не используется — коллекции, реализующие IDictionary, ориентируются в первую очередь на обращение по ключу, а не на последовательный перебор элементов. По этой причине интерфейс IDictionary зависит от интерфейса IDic-tionaryEnumerator, который расширяет Enumerator и дополняет его тремя новыми свойствами:

  • Entry: возвращает пару «ключ/значение» для текущего элемента словаря.
  • Key: возвращает текущий ключ.
  • Value: возвращает ссылку на текущее значение.
  • В .NET Framework входит класс DictionaryBase. Определяя класс производным от DictionaryBase, вы получаете в свое распоряжение всю функциональность интерфейса IDictionary.

    Члены класса IDictionary перечислены в табл. 5.4.

    Поскольку ключи в ассоциативных коллекциях должны быть уникальными, при реали-зации большинства методов необходимо сначала проверить, не был ли заданный ключ использован ранее. Свойство Keys возвращает объект, реализующий ICollection; уникальность ключа проверяется методом,Соп1а1п5 интерфейса ICollection.

    Таблица 5.4. Члены интерфейса IDictionary

    Метод/свойство

    Описание

    IsFixedSize (свойство)

    Логическое свойство. Показывает, имеет ли коллекция фиксированный размер

    IsReadOnly (свойство)

    Логическое свойство. Показывает, доступна ли коллекция только для чтения

    Item (свойство)

    Свойство доступно для чтения и записи. Используется для получения и присваивания значения объекта с заданным индексом

    Keys (свойство)

    Возвращает объект, реализующий интерфейс ICollection и содержащий все ключи ассоциативной коллекции

    Values (свойство)

    Возвращает объект, реализующий интерфейс ICollection и содержащий все значения ассоциативной коллекции

    Add(ByVal key As Object, ByVal value As Object) (метод)

    Добавляет объект с заданным ключом (ключ должен быть уникальным)

    Clear (метод)

    Удаляет все элементы из ассоциативной коллекции

    Contains (ByVal key As Object) As Boolean (метод)

    Ищет значение с заданным ключом

    GetEnumerator (метод)

    Возвращает объект IDictionaryEnumerator для работы с ключами и значениями

    Remove(ByVal key As Object) (метод)

    Удаляет элемент с заданным ключом

     

    IComparable

    Предположим, коллекцию объектов Employee потребовалось отсортировать по заработной плате. Конечно, операцию сортировки было бы удобно реализовать непосредственно в классе Emplоуее, чтобы сортировка простого или динамического массива объектов этого класса выполнялась так же просто, как сортировка строковых массивов. Оказывается, порядок сортировки элементов, используемый методом Sort классов Array и ArrayList, определяется интерфейсом IComparable (строковые массивы интерфейс IComparabl e сортирует в порядке ASCII-кодов). Интерфейс состоит из единственного метода CompareTo: Function CompareTo(ByValobj As Object) As Integer Метод возвращает следующие значения:

  • отрицательное число, если текущий экземпляр меньше заданного объекта;
  • ноль, если текущий экземпляр равен заданному объекту;
  • положительное число, если текущий экземпляр больше заданного объекта.
  • Следующая версия класса Employee реализует интерфейсы lEnumerable и IComparable и сортирует массив по убыванию заработной платы:

    Public Class Employee

    Implements IComparable

    Private m_Name As String

    Private m_Salary As Decimal

    Private Const LIMIT As Decimal =0.10

    Public Sub New(ByVal theName As String,ByVal curSalary As Decimal)

    m_Name = theName m_Salary = curSalary

    End Sub

    Public Function CompareTo(ByVal anEmployee As Object) As Integer _

    Implements IComparable.CompareTo

    If CType(anEmployee,Employee).Salany < Me.Salary Then Return -1

    El self CTypetanEmployee.Employee).Salary = Me.Salary Then

    Return 0

    Elself CTypeCanEmployee,Employee).Salary > Me.Salary Then

    Return 1

    End If

    End Function

    Public Readonly Property TheName() As String Get

    Return m_Name End Get End Property

    Public Readonly Property Salary() As Decimal Get

    Return MyClass.m_Salary

    End Get End Property

    Public Overridable Overloads Sub RaiseSalary(ByVal Percent As Decimal)

    If Percent > LIMIT Then

    ' Операция запрещена - необходим пароль

    Console.WriteLine("NEED PASSWORD TO RAISE SALARY MORE " & _

    "THAN LIMIT!!!!")

    Else

    m_Salary =(1 + Percent) * m_Salary

    End If

    End Sub

    Public Overridable Overloads Sub RaiseSalary(ByVal Percent As Decimal._

    ByVal Password As String) If Password = "special" Then

    m_Salary =(1 + Percent) * m_Salary

    End If

    End Sub

    End Class

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

    Sub Main()

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

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

    Dim joe As New Employee("Joe", 20000)

    Dim gary As New Employее("Gary", 1)

    Dim theEmployees() As Employee = _

    {torn, sally, joe. gary}

    Array.Sort(theEmployees)

    ' Порядок сортировки определяется CompareTo!

    Dim aEmployee As Employee

    For Each aEmployee In theEmployees

    Console.WriteLine(aEmployee.TheName & "has yearly salary $"

    & FormatNumbertaEmployee.Salary)) Next

    Console.ReadLine()

    End Sub

    Результат показан на рис. 5.9.

    Рис. 5.9. Сортировка по нестандартному критерию с использованием IComparable

     

    Интерфейс IComparer

    .NET Framework позволяет выполнять сортировку по нескольким критериям. Например, чтобы упорядочить массив работников сначала по заработной плате, а затем по имени (в группах с одинаковой зарплатой) следует реализовать интерфейс IComparer, содержащий единственный метод СотрагеТо. При этом вы сможете воспользоваться одной из перегруженных версий Array. Sort (или ArrayList. Sort), которая имеет следующую сигнатуру:

    Public Shared Sub Sort(ByVal array As Array. ByVal comparer As IComparer)

    Обычно в программе создается отдельный класс, реализующий IComparer, и экземпляр этого класса передается методу Sort. Пример такого класса приведен ниже. Обратите внимание на выделенную строку — в ней имена работников передаются в виде строк методу Compare класса String:

    Public Class SortByName

    Implements IComparer

    Public Function CompareTo(ByVal firstEmp As Object.ByVal

    secondEmp=As Object) As Integer Implements IComparer.Compare

    Dim temp1 As Employee = CType(firstEmp,Employee)

    Dim temp2 As Employee = CType(secondEmp.Employee)

    Return

    String.Compare(templ.TheName. temp2.TheName)

    End Function

    End Class

    Пример процедуры Sub Main с использованием этого класса:

    SubMain()

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

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

    Dim sam As New Employee("Sam". 60000)

    Dim ted As New Employee("Ted". 50000)

    Dim theEmployees() As Employee = _

    {torn.sally,sam.ted}

    Array.Sort(theEmployees)

    Dim SortingByName As SortByName = New SortByName()

    Array.Sort(theEmployees,SortingByName)

    Dim aEmployee As Employee

    For Each aEmployee In theEmployees

    Console.WriteLine(aEmployee.TheName & "has yearly salary $" &

    FormatNumberCaEmployee.Salary))

    Next

    Console. ReadLine() End Sub .

    Результат показан на рис. 5.10,

    Рис. 5.10. Сортировка по нескольким критериям с использованием IComparer

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