Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование. Введение в разработку на C#. Учебное пособие
.pdf
В примере складываются координаты двух точек, чтобы получилась
координата новой. Если мы добавим новый метод в класс Point, а в Pro-
gram напишем:
Point P2d_1 = new Point(1, 2);
Point P2d_2 = new Point(3, 4);
Point P2d_3 = P2d_1 + P2d_2;
P2d_3.Direction();
то на консоль выведется «Координата по X = 4, Y = 6»
Все перегрузки операторов являются статическими методами
класса. Кроме того, следует учесть, что если перегружается оператор
равенства (==), то необходимо перегрузить и оператор неравенства (!=).
Операторы < и >, а также <= и >= тоже следует перегружать парами.
Ниже приведен полный список операторов, которые можно
перегрузить:
Унарные операторы: +, -, !, ~, ++, --, true, false.
Бинарные операторы: +, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, <=.
12.4. Вопросы для самопроверки
1. Поддерживает ли язык C# полиморфизм? Подкрепите свою точку
зрения примерами кода на языке C#.
2. Каковы определения внутренней и внешней общности?
3. Являются ли перегрузки операторов нестатическими членами
класса?
12.5. Задания для самопроверки
1. Покажите действие принципа полиморфизма на объектах из за-
дания 1 раздела 9.
2. Опишите биологические процессы объектов задания 1 раздела 9
перегрузками методов.
91

13. КОЛЛЕКЦИИ: ВИДЫ И НАЗНАЧЕНИЕ
13.1. Понятие коллекций
В предыдущих разделах рассматривалось создание структур данных и манипуляции ими. В данном разделе рассматриваются предварительно распределенные по пакетам классы структур данных, предоставленные .NET Framework. Эти классы называются коллекциями классов (collection classes): в них сохранены коллекции данных. Каждый экземпляр одного из этих классов называется коллекцией, представляющей собой набор элементов. С помощью коллекций классов вместо создания структур данных программист просто использует существующие
структуры данных, не заботясь об их реализации. Данная методология
представляет собой замечательный пример повторного использования
кода. Разработчики тратят гораздо меньше времени на написание кодов
и ожидают очень высокой производительности за счет доведения до
максимума скорости исполнения и сведения к минимуму потребления
ресурсов памяти.
Некоторыми примерами коллекций являются карты в карточной
игре, любимые песни, сохраненные на компьютере, а также записи о
недвижимости в реестре сделок. MS .NET Framework предоставляет го-
товые компоненты многократного использования; разработчику нет необходимости записывать собственные коллекции классов. Коллекции
стандартизированы, поэтому их легко использовать в любых программных приложениях, не вдаваясь в подробности реализации. Коллекции
создаются для многократного применения. Они настроены на оперативное исполнение, а также на эффективное использование ресурсов памяти.
92

13.2. Типы коллекций
Следует тщательно выбирать класс коллекции. Использование
неправильного типа может привести к ограничению возможностей
использования коллекции. В общем случае не следует использовать
типы в пространстве имен System.Collections, если явным образом не
нужна платформа .NET Framework версии 1.1. Предпочитаются
универсальная и параллельная версии коллекции, так как они обладают
большей типобезопасностью и содержат другие улучшения.
Необходимо ответить на следующие вопросы:
• Нужен ли последовательный список, элемент которого обычно
удаляется сразу после извлечения его значения?
– Если да, то рассмотрите возможность использования класса
Queue или универсального класса Queue(Of T), если требуется
поведение по принципу «первым поступил – первым обслужен» (FIFO).
Рассмотрите возможность использования класса Stack или
универсального класса Stack(Of T), если требуется поведение по
принципу «последним поступил – первым обслужен» (LIFO). Для
безопасного доступа из нескольких потоков следует использовать
параллельные версии классов ConcurrentQueue(Of T) и
ConcurrentStack(Of T).
– Если нет, то следует выбирать из остальных типов коллекций.
• Нужен ли доступ к элементам в определенном порядке (FIFO,
LIFO) или в произвольным порядке?
– Класс Queue, универсальный класс Queue(Of T) или
универсальный класс ConcurrentQueue(Of T) предоставляют доступ по
принципу FIFO. Дополнительные сведения см. в разделе
«Преимущества использования потокобезопасных коллекций».
– Класс Stack, универсальный класс Stack(Of T) или универсальный
класс ConcurrentStack(Of T) предоставляют доступ по принципу LIFO.
Дополнительные сведения см. в разделе «Преимущества использования
потокобезопасных коллекций».
93

– Универсальный класс LinkedList(Of T) предоставляет
последовательный доступ от начала к концу списка или наоборот.
• Необходимо ли иметь доступ к каждому элементу по индексу?
– Классы ArrayList и StringCollection, и универсальный класс List(Of
T) предоставляют доступ к своим элементам по индексу с отсчетом от
нуля.
– Классы Hashtable, SortedList, ListDictionary и StringDictionary, а
также универсальные классы Dictionary(Of TKey, TValue) и
SortedDictionary(Of TKey, TValue) предоставляют доступ к своим
элементам по ключу.
– Классы NameObjectCollectionBase и NameValueCollection, а также
универсальные классы KeyedCollection(Of TKey, TItem) и SortedList(Of
TKey, TValue) предоставляют доступ к своим элементам по индексу с
отсчетом от нуля или по ключу.
• Будет ли каждый элемент содержать только одно значение,
сочетание из одного ключа и одного значения или сочетание из одного
ключа и нескольких значений?
– Одно значение. Можно использовать любую из коллекций,
основанных на интерфейсе IList или на универсальном интерфейсе
IList(Of T).
– Один ключ и одно значение. Можно использовать любую из
коллекций, основанных на интерфейсе IDictionary или на
универсальном интерфейсе IDictionary(Of TKey, TValue).
– Одно значение с внедренным ключом. Можно использовать
универсальный класс KeyedCollection(Of TKey, TItem).
– Один ключ и несколько значений. Можно использовать класс
NameValueCollection.
• Нужна ли возможность отсортировать элементы в порядке,
отличном от порядка их поступления?
– Класс Hashtable сортирует свои элементы по их хэш-коду.
– Класс SortedList и универсальные классы SortedDictionary(Of
TKey, TValue) и SortedList(Of TKey, TValue) сортируют свои элементы по
94

их ключам на основе реализации интерфейса IComparer и
универсального интерфейса IComparer(Of T).
– ArrayList предоставляет метод Sort, который принимает
реализацию IComparer в качестве параметра. Его универсальный аналог
– универсальный класс List(Of T) предоставляет метод Sort, который
принимает реализацию универсального интерфейса IComparer(Of T) в
качестве параметра.
• Необходимы ли быстрый поиск и извлечение данных?
– ListDictionary быстрее, чем Hashtable для небольших коллекций
(10 элементов или меньше). Универсальный класс Dictionary(Of TKey,
TValue) предоставляет более быстрый просмотр, чем универсальный
класс SortedDictionary(Of TKey, TValue). Многопотоковой реализацией
является класс ConcurrentDictionary(Of TKey, TValue). Класс
ConcurrentBag(Of T) предоставляет быструю многопотоковую вставку
для неупорядоченных данных.
• Нужна ли коллекция только для хранения строк?
– Классы StringCollection (основанный на IList) и StringDictionary
(основанный на IDictionary) находятся в пространстве имен
System.Collections.Specialized.
– Кроме того, можно использовать любой из универсальных
классов коллекций в пространстве имен System.Collections.Generic как
строго типизированную строковую коллекцию, указав класс String в
качестве аргумента универсального типа.
13.3. Примеры работы с коллекциями
В большинстве языков программирования обычные массивы имеют
фиксированный размер: их нельзя изменять динамически для соответствия требованиям времени исполнения и необходимой памяти программному приложению. В некоторых приложениях ограничение по
размеру представляет собой довольно серьезную проблему для разработчиков. Им приходится выбирать между применением массивов достаточно большого фиксированного размера для сохранения максималь-
95

ного числа элементов, которое может потребоваться программе, и использованием динамических структур данных, которые могут расширять и сокращать объем памяти, необходимый для сохранения данных в
ответ на изменяющиеся требования программы во время исполнения.
Коллекция класса ArrayList .NET Framework имитирует функцио-
нальность традиционных массивов и обеспечивает динамическое изменение размера коллекции посредством методов класса. В любой момент
времени коллекция ArrayList содержит определенное число элементов,
меньшее или равное емкости – количеству элементов, зарезервированных в текущее время для коллекции ArrayList. Программа может манипулировать емкостью посредством свойства Capacity класса ArrayList.
При необходимости расширения класса ArrayList текущая емкость (ca-
pacity) удваивается по умолчанию. Особенностями работы динамического массива является то, что результатом вставки в класс ArrayList
дополнительных элементов с текущим размером, меньшим, чем емкость, становится ускорение выполнения операции, а операция вставки
в класс ArrayList элемента, который должен расширяться для соответствия новому элементу, выполняется достаточно медленно.
Можно воспользоваться методом TrimToSize класса ArrayList для
установки точного размера (подгонки) класса ArrayList. При этом оптимизируется использование памяти класса ArrayList. Здесь следует соблюдать осторожность: если программа должна вставить дополнительные элементы, то процесс замедлится, потому что класс ArrayList должен расширяться динамически (подгонка не оставляет места для расширения).
Приращение емкости по умолчанию – удвоение размера класса Ar-
rayList – может показаться пустым расходом пространства для сохранения, однако удвоение емкости является эффективным способом быстрого расширения класса ArrayList «практически до нужного размера».
При этом использование времени становится более эффективным, нежели при увеличении размера класса ArrayList по одному элементу во
время ответа на операции вставки.
96

Все классы являются производными от класса Object, поэтому
класс ArrayList может содержать объекты любого типа. В табл. 13.1 перечислены некоторые полезные методы класса ArrayList.
Таблица 13.1
Основные методы класса ArrayList
Метод Описание
Add Добавление объекта в класс ArrayList
Clear Удаление всех элементов из класса ArrayList
Contains Возвращение значения true(false), если указанный объект ob-
ject находится (отсутствует) в классе ArrayList
IndexOf Возвращение указателя первого появления указанного объек-
та в классе ArrayList
Insert Вставка объекта object согласно заданному индексу
Remove Удаление первого появления указанного объекта
RemoveAt Удаление объекта по заданному индексу
RemoveRange Удаление заданного количества элементов, начиная с заданно-
го индекса в классе ArrayList
Sort Сортировка класса ArrayList
TrimToSize Задание емкости (Capacity) класса ArrayList текущим количе-
ством элементов в классе
Давайте создадим динамический массив и проделаем следующий набор операций: поместим туда 5 чисел; одну строку по индексу 3; удалим
элемент по индексу 0; удалим элемент 4; перевернем элементы массива в
зеркальном порядке.
ArrayList aList = new ArrayList();
for (int i = 0; i < 5; i++)
aList.Add(i);
aList.Insert(3, "Строка");
aList.RemoveAt(0);
aList.Remove(4);
aList.Reverse();
97

//Вывод на экран
foreach(object obj in aList)
Console.Write(obj + " ");
Console.Write(aList.IndexOf("Строка"));
Теперь на экране мы получим 3 “Строка” 2 1 1. Обратите внимание
на последнюю единицу – это индекс элемента «Строка», но ведь мы ее
добавляли по индексу 3. Все дело в том, что динамический массив сам
уплотняется, не оставляя пустых мест внутри себя после удаления.
13.4. Вопросы для самопроверки
1. Когда следует использовать типы в пространстве имен
System.Collections?
2. Какой тип коллекций используется для создания буферов типа
FIFO? Для типа LIFO?
3. Для каких целей следует использовать Dictionary(Of TKey,
TValue)?
4. Какие классы коллекций поддерживают автоматическую сорти-
ровку? В чем принципиальное различие алгоритмов сортировки?
5. В каком классе коллекций следует хранить строки?
6. Как классу ArrayList удается хранить разные типы данных?
13.5. Задания для самопроверки
1. Добавьте в реализацию задания 2 из раздела 5 возможность
динамического добавления вопросов перед тестированием.
Формирование вопросов и непосредственно тестирование проводится
рамках одной сессии.
2. Создайте программу – телефонный справочник, наполнение
которого и чтение выполняется в рамках одной сессии. Поиск в книге
должен осуществляться как по имени персоны, так и по номеру.
98

3. Модифицируйте программу из предыдущего задания так, чтобы
для одной персоны можно было назначить несколько телефонных
номеров с описаниями типа «домашний», «рабочий».
4*. Разработайте приложение, использующее стек для обхода дерева в
глубину. Тип для узла дерева содержит поле для коллекции ссылок на
своих потомков и поле для имени узла. Обход дерева осуществляется в
цикле до тех пор, пока стек не пуст. В цикле из стека достаётся узел дерева, выдаётся имя узла, потомки узла добавляются в стек.
5*1. Разработайте приложение, использующее очередь для обхода дерева в ширину. Тип для узла дерева содержит поле для коллекции ссылок на своих потомков и поле для номера узла. Обход дерева осуществляется в цикле до тех пор, пока очередь не пуста.
1
Звездочка указывает на задачи с повышенной сложностью.
99

14. GENERICS. LAMBDA. LINQ
14.1. Обобщенные типы
Обобщенные типы (англ. Generics) – особые типы, которые
определяют взаимодействия для нескольких типов. Они также известны
как шаблонные типы. Основное их предназначение – описывать
взаимодействия над однородными типами без дублирования кода.
Классическим примером использования обобщенных типов являются
арифметические операции над различными типами данных. Например:
public class Summator<T>
{
public T Sum(T o1, T o2)
{
return o1 + o2;
}
}
Такой класс может выполнять операции сложения над типами int,
long, double и другими:
Summator<int> si = new Summator<int>();
si.Sum(2, 4);
Summator<float> sf = new Summator<float>();
si.Sum(2.3, 1.2);
Generics получили широкое распространение на практике для
оперирования коллекциями:
List<int>, List<Student>
В настоящее время на основе шаблонных типов работают такие
сложные механизмы, как транслирование объектов из БД в память,
преобразование одних типов к другим через явно описанные правила,
регистрация сервисов и компонент для вызова из любой точки
100
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
