ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
// Этот вспомогательный класс используется для сортировки
// массива объектов Car по названию.
using System.Collections;
public class PetNameComparer : IComparer {
public PetNameComparer() {}
// Проверка названий объектов.
int IComраrer.Compare(object o1, object o2) {
Car t1 = (Car)о1;
Car t2 = (Car)o2;
return String.Compare (t1.petName, t2.petName);
}
}
Этот вспомогательный класс можно использовать в программном коде пользователя объекта. Класс System.Array предлагает перегруженный метод Sort(), один из вариантов которого допускает использование объекта, реализующего интерфейс IComparer (рис. 7.11).
static void Main (string[] args) {
…
// Теперь сортируем по имени.
Array.Sort(myAutos, new РеtNameComparer());
// Вывод отсортированного массива.
Consolе.WriteLine("nУпорядочение по названию");
foreach(Car e in myAutos) Console.WriteLine("{0} {1}", c.ID, c.petName);
…
}
Рис. 7.11. Сортировка автомобилей по названию
Типы, определяющие сортировку, и пользовательские свойства
Следует отметить, что с помощью пользовательских статических свойств вы можете помочь пользователю объекта отсортировать типы Car по заданному элементу данных. Предположим, что в класс Car добавлено статическое свойство SortByPetName(), доступное только для чтения и возвращающее экземпляр объекта, реализующего интерфейс IComparer (в данном случае это PetNameComparer).
// Здесь обеспечивается поддержка пользовательского свойства для
// возвращения "правильного" интерфейса IComparer.
public class Car: IComparable {
…
// Свойство, возвращающее компаратор SortByPetName.
public static IComparer SortByPetName { get { return (IComparer)new PetNameComparer(); } }
}
В программном коде пользователя объекта теперь можно выполнить сортировку по названию, используя ассоциированное свойство без какого бы то ни было "упоминания" специального типа класса PetNameComparer:
// Сортировка по имени становится немного проще.
Array.Sort(myAutos, Car.SortByPetName);
Исходный код. Проект ComparableCar размещен в подкаталоге, соответствующем главе 7.
Теперь вы должны понимать не только то, как определяются и реализуются типы интерфейса, но и то, в чем их польза. Будьте уверены, интерфейсы можно обнаружить в любом из главных пространств имен .NET и в завершение этой главы мы рассмотрим примеры интерфейсов (и базовых классов) из пространства имен System.Collections.
Интерфейсы из пространства имен System.Collections
В качестве самого примитивного контейнера может выступать тип System.Array. В главе 3 было показано, что класс System.Array предлагает целый ряд соответствующих возможностей (таких, как инвертирование, сортировка, очистка и перечисление). Но класс Array имеет свои ограничения, и наиболее важным из них является невозможность динамического переопределения размеров при добавлении и удалении элементов. Если для хранения типов необходим более "гибкий" контейнер, лучше использовать типы, определенные в пространстве имен System.Collections (или, в соответствии с рекомендациями главы 10, из пространства имен System.Collections.Generic).
Пространство имен System.Collections определяет целый ряд интерфейсов (и некоторые из них уже использовались в примерах этой главы). Как правило, коллекции классов реализует эти интерфейсы для того, чтобы обеспечить доступ к своему содержимому. В табл. 7.2. приводятся описания основных интерфейсов, относящихся к коллекциям.
Таблица 7.2. Интерфейсы System.Collections
Интерфейс Описание ICollection Определяет общие характеристики (такие, как защищенность счетчиков и цепочек) для типа коллекции IComparer Позволяет сравнение двух объектов IDictionary Позволяет объекту представить его содержимое с помощью пар имен и значений IDictionaryEditor Перечисляет содержимое типа, поддерживающего IDictionary IEnumerable Возвращает интерфейс IEnumerator для данного объекта IEnumerator Обеспечивает общую поддержку перечисления подтипов с помощью foreach IHashCodeProvider Возвращает хеш-код для реализующего типа, используя настраиваемый механизм хеширования IKeyComparer Этот интерфейс является новым в .NET 2.0). Объединяет функциональные возможности IComparer и IHashCodeProvider, чтобы обеспечить сравнение объектов по их хеш-кодам (если объекты (равны, то они должны возвращать одинаковые хеш-коды) IList Обеспечивает возможность добавления, удаления и индексирования элементов в списке объектов. Кроме того, с помощью членов этого интерфейса можно выяснить, является ли данный тип-контейнер коллекции доступным только для чтения, и имеет ли он фиксированный размерМногие из этих интерфейсов связаны иерархией интерфейсов, в то время как другие являются автономными единицами. На рис. 7.12 показана схема взаимосвязей между указанными типами (напомним, что один интерфейс может быть производным от нескольких интерфейсов).
Рис. 7.12. Иерархия интерфейсов System.Collections
Интерфейс ICollection
Интерфейс ICollection является простейшим интерфейсом пространства имен System.Collections в том смысле, что этот интерфейс определяет поведение, поддерживаемое любым типом коллекции. По сути, этот интерфейс обеспечивает узкий набор свойств, которые позволяют определить: а) число элементов в контейнере; б) защищенность цепочки контейнера; в) возможность копирования содержимого в тип System.Array. Формально ICollection определяется так, как показано ниже (обратите внимание на то, что ICollection расширяет IEnumerable).
public interface ICollection : IEnumerable {
// Член IEnumerable.…
int Count { get; }
bool IsSynchronized { get; }
object SyncRoot { get; }
void CopyTo(Array array, int index);
}
Интерфейс IDictionary
Вы, возможно, знаете, что словарь - это коллекция, обеспечивающая поддержку пар имен и их значений. Например, можно построить пользовательский тип, реализующий IDictionary, в котором вы сможете сохранить типы Car (значения) с возможностью их последующего восстановления по ID или petName (это примеры имен). Интерфейс IDictionary определяет свойства Keys и Values, а также методы Add(), Remove() и Contains(). Отдельные элементы можно получить c помощью индексатора типа. Вот формальное определение.
public interface IDictionary : ICollection, IEnumerable {
bool IsFixedSize { get; }
bool IsReadOnly { get; }
object this [object key] { get; set; }
ICollection Keys { get; }
ICollection Values { get; }
void Add(object key, object value);
void Clear();
bool Contains(Object key);
IDictionaryEnumerator GetEnumerator();
void Remove(object key);
}
Интерфейс IDictionaryEnumerator
При внимательном чтении вы могли заметить, что IDictionary.GetEnumerator() возвращает экземпляр IDictionaryEnumerator. Тип IDictionaryEnumerator – это строго типизованный нумератор, расширяющий IEnumerator путем добавления следующей функциональной возможности.
public interface IDictionaryEnumerator : IEnumerator {
// Методы IEnumerator…
DictionaryEntry Entry { get; }
object Key { get; }
object Value { get; }
}
Обратите внимание на то, что IDictionaryEnumerator обеспечивает возможность перечисления элементов словаря с помощью общего свойства Entry, которое возвращает тип класса System.Collections.DictionaryEntry. Кроме того, вы можете выполнить цикл по парам имен и значений, используя свойства Key/Value.
Интерфейс IList
Последним из ключевых интерфейсов System.Collections является интерфейс IList, который обеспечивает возможность вставки, удаления и индексирования элементов контейнера.
public interface IList : ICollection, IEnumerable {
bool IsFixedSize { get; }
bool IsReadOnly { get; }
object this[int index] { get; set; }
int Add(object value);
void Clear();
bool Contains(object value);