
- •Оглавление
- •Об авторе
- •Посвящение
- •Благодарности
- •Ждем ваших отзывов!
- •Что такое .NET
- •Создание исходной программы
- •Тестовая поездка
- •Каркас программы
- •Комментарии
- •Введение в хитрости панели элементов
- •Повторное использование кода из панели элементов
- •Правила объявления переменных
- •Вариации на тему int
- •Объявление переменной с плавающей точкой
- •Ограничения переменных с плавающей точкой
- •Объявление переменных типа decimal
- •Сравнение десятичных и целых чисел, а также чисел с плавающей точкой
- •Логичен ли логический тип
- •Символьные типы
- •Что такое тип-значение
- •Неизменяемость строк
- •Основные операции над строками
- •Сравнение строк
- •Сравнение без учета регистра
- •Отличие строк в разных регистрах
- •Преобразование символов строки в символы верхнего или нижнего регистра
- •Поиск в строках
- •Как искать
- •Пуста ли строка
- •Удаление пробельных символов
- •Анализ числового ввода
- •Обработка последовательности чисел
- •Объединение массива строк в одну строку
- •Арифметика
- •Простейшие операторы
- •Порядок выполнения операторов
- •Оператор инкремента
- •Сравнение чисел с плавающей точкой
- •Составные логические операторы
- •Вычисление типа операции
- •Типы при присваивании
- •Перегрузка операторов
- •Ветвление с использованием if и switch
- •Инструкция if
- •Инструкция else
- •Как избежать else
- •Вложенные инструкции if
- •Конструкция switch
- •Циклы
- •Цикл без счетчика
- •Правила области видимости
- •Пример
- •Зачем нужны разные циклы
- •Зачем нужны массивы
- •Массив фиксированного размера
- •Массив переменного размера
- •Свойство Length
- •Инициализация массивов
- •Понятие <т>
- •Обобщенные коллекции
- •Инстанцирование пустого списка
- •Создание списка целых чисел
- •Преобразования списков в массивы и обратно
- •Подсчет количества элементов в списке
- •Поиск в списках
- •Инициализаторы массивов и коллекций
- •Выполнение специфичных для множеств задач
- •Создание множества
- •Добавление элемента в множество
- •Выполнение объединения
- •Пересечение множеств
- •Получение разности
- •Не используйте старые коллекции
- •Обход каталога файлов
- •Начало программы
- •Получение начальных входных данных
- •Создание списка файлов
- •Форматирование вывода
- •Вывод в шестнадцатеричном формате
- •Обход коллекций: итераторы
- •Доступ к коллекции: общая задача
- •Использование foreach
- •Формат индексатора
- •Блок итератора
- •Создание каркаса блока итератора
- •Итерирование дней в месяцах
- •Что же такое коллекция
- •Синтаксис итератора
- •Блоки итераторов произвольного вида и размера
- •Обобщенные классы безопасны
- •Обобщенные классы эффективны
- •Очередь с приоритетами
- •Распаковка пакета
- •Написание обобщенного кода
- •Использование простого необобщенного класса фабрики
- •Незавершенные дела
- •Ковариантность
- •Использование механизма исключений для сообщения об ошибках
- •Что происходит при генерации исключения
- •Исключительный пример
- •Что делает этот пример "исключительным"
- •Трассировка стека
- •Советы по написанию кода с хорошей обработкой ошибок
- •Анализ возможных исключений метода
- •Как выяснить, какие исключения генерируются теми или иными методами
- •Генерирующие исключения выражения
- •Работа с перечислениями
- •Создание перечислений с инициализаторами
- •Указание типа данных перечисления
- •Применение перечислений в конструкции switch
- •Процедурные поездки
- •Объектно-ориентированные поездки
- •Определение класса и объекта
- •Определение класса
- •Что такое объект
- •Различие между объектами
- •Работа со ссылками
- •Классы, содержащие классы
- •Определение константных членов-данных и членов-данных только для чтения
- •Передача аргументов методу
- •Передача методу нескольких аргументов
- •Соответствие определений аргументов их использованию
- •Перегрузка методов
- •Реализация аргументов по умолчанию
- •Возврат значения оператором return
- •Кортеж с двумя элементами
- •Создание кортежей более чем с двумя элементами
- •Глава 14 Поговорим об этом
- •Определение методов
- •Определение статического метода
- •Определение метода экземпляра
- •Полное имя метода
- •Ключевое слово this
- •Когда this используется явно
- •Что делать при отсутствии this
- •Использование локальных функций
- •Прочие уровни безопасности
- •Методы доступа
- •Пример управления доступом
- •Выводы
- •Статические свойства
- •Побочные действия свойств
- •Дайте компилятору написать свойства для вас
- •Методы и уровни доступа
- •Замена конструктора по умолчанию
- •Конструирование объектов
- •Непосредственная инициализация объекта
- •Конструирование с инициализаторами
- •Инициализация объекта без конструктора
- •Определение свойств с кодом
- •Определение конструкторов и деструкторов с кодом
- •Определение методов доступа к свойствам с кодом
- •Определение методов доступа к событиям с кодом
- •Наследование класса
- •Более сложный пример наследования
- •ЯВЛЯЕТСЯ или СОДЕРЖИТ
- •Доступ к BankAccount через содержание
- •Отношение СОДЕРЖИТ
- •Заменяемость классов
- •Неверное преобразование времени выполнения
- •Указание конкретного конструктора базового класса
- •Обновленный класс BankAccount
- •Перегрузка унаследованного метода
- •Простейший случай перегрузки метода
- •Различные классы, различные методы
- •Сокрытие метода базового класса
- •Вызов методов базового класса
- •Что неверно в стратегии использования объявленного типа
- •Использование is для полиморфного доступа к скрытому методу
- •Объявление метода виртуальным и перекрытие
- •Получение максимальной выгоды от полиморфизма
- •Разложение классов
- •Абстрактный класс: ничего, кроме идеи
- •Как использовать абстрактные классы
- •Создание абстрактных объектов невозможно
- •Опечатывание класса
- •Реализация интерфейса
- •Именование интерфейсов
- •Наследование и реализация интерфейса
- •Преимущества интерфейсов
- •Тип, возвращаемый методом
- •Что скрыто за интерфейсом
- •Гибкие зависимости через интерфейсы
- •Реализация отношения СОДЕРЖИТ с помощью интерфейсов
- •Определение делегата
- •Пример передачи кода
- •Делегирование задания
- •Очень простой первый пример
- •Более реальный пример
- •Создание приложения
- •Жизненный цикл делегата
- •Анонимные методы
- •Проектный шаблон Observer
- •Что такое событие. Публикация и подписка
- •Как издатель оповещает о своих событиях
- •Как подписаться на событие
- •Как опубликовать событие
- •Как наблюдатели "обрабатывают" событие
- •Сборки
- •Выполнимые файлы
- •Библиотеки классов
- •Создание проекта библиотеки классов
- •Создание автономной библиотеки классов
- •Создание классов для библиотеки
- •Использование тестового приложения
- •Дополнительные ключевые слова для управления доступом
- •protected: поделимся с подклассами
- •protected internal: более изощренная защита
- •Размещение классов в пространствах имен
- •Объявление пространств имен
- •Пространства имен и доступ
- •Использование полностью квалифицированных имен
- •Ссылочные типы
- •Выходные параметры
- •Альтернативные методы возврата значений
- •Работа с переменными out
- •Возврат значений по ссылке
- •Различия типов-значений
- •Когда следует использовать структуры
- •Добавление распространенных элементов структур
- •Управление отдельной записью
- •Добавление структур в массивы
- •Перекрытие методов
- •Определение того, что следует защищать
- •Документирование компонентов программы
- •Разложение компонентов на функции
- •Оценка рисков
- •Аутентификация с использованием входа в Windows
- •Безопасность развертывания
- •Уязвимости сценариев
- •Наилучшие методы защиты приложений Web Forms
- •Получение данных
- •Настройка образца схемы базы данных
- •Подключение к источнику данных
- •Работа с визуальными инструментами
- •Написание кода для работы с данными
- •Использование Entity Framework
- •Где водится рыба: файловые потоки
- •Потоки
- •Читатели и писатели
- •Пример использования потока
- •Как это работает
- •Наконец-то мы пишем!
- •Использование конструкции using
- •Загрузка файла из Интернета
- •Регистрация сетевой активности
- •Графика
- •Перья
- •Кисти
- •Текст
- •Классы рисования и каркас .NET
- •Приступая к работе
- •Настройка проекта
- •Обработка счета
- •Создание подключения к событию
- •Рисование доски
- •Запуск новой игры

Что же такое коллекция
Остановимся на минутку и сравним эту небольшую коллекцию с коллекци ей "аапен,х теinрассмотренной выше в главе. В то время как -Сапен-Стрnимеет сложную структуру узлов, связанных посредством указателей, приведенная простейшая коллекция месяцев основана на простом массиве с фиксирован ным содержимым. Но понятие коллекции оказывается существенно шире.
Ваш класс коллекции не обязан иметь фиксированное содержимое - боль шинство коллекций разработаны для хранения объектов путем добавления их в коллекции, например, с помощью метода гннnи иилиn чего-то в этом роде. Класс ьефенгл лофinк примеру, использует для добавления элементов в коллекцию ин дексатор. Ваша коллекция также должна обеспечивать метод гннnа и какi n и блок итератора, чтобы вы могли работать с ней с помощью цикла цдлеоучьn
Цель коллекции в наиболее общем смысле заключается в хранении мно жества объектов и обеспечении возможности их последовательного обхода по одному, хотя иногда может использоваться и произвольная выборка, как в де монстрационной программе .ане-елр(nКонечно, массив и так в состоянии спра виться с этим, без дополнительных "наворотов" наподобие класса лдаечмофтcn но итераторы вполне могут применяться и за пределами примера лда рччофтmяn
Говоря более обобщенно, независимо от того, что именно происходит за сценой, итерируемая коллекция генерирует "поток" значений, который мож но получить с помощью сдлеодчыЧтобыn лучше понимать данную концепцию, ознакомьтесь с еще одним примером простого класса из демонстрационной программы д щелощдлйгдуптекотn орый иллюстрирует чистую идею коллекции:
ц ц6 |
Uыхим1п3 имm |
: |
цц |
6 х\1имп3 имm |
|
(rщ |
|
|
( |
|
|
("hё |
и""x |
;(={ (""и="Tи |
|
("hё |
и""x |
hT |
; |
("hё |
и""x |
(;= |
"=hh { |
("hё |
и""x |
" =" |
=иё |
("hё |
и""x |
|
|
Коллекция зен аа:eчоа Атркакn ни странно, ничего не юiNт2e в обычном смысле этого слова. В ней нет даже массива. Так где же здесь коллекция? Она - в последовательности вызовов фlеконаерn :аВтnиспользующих специаль ный новый синтаксис для возврата элементов один за другим, пока все они не будут возвращены вызывающему методу. Эта коллекция "содержит" пять
ГЛАВА 7 Работа с коллекция ми 191

объектов, каждый из которых представляет собой простую строку, как и в рас смотренном только что примере MonthDays. Извне класса, в методе Main ( ) , вы можете итерировать эти объекты посредством простого цикла foreach, поскольку конструкция yield return возвращает по одной строке за раз. Вот часть метода Main ( ) , в которой выполняется итерирование "коллекции" StringChunks:
, , |
о |
, wП |
|
||
, , |
r |
> |
, , |
|
|
y |
, ы |
ы ,П |
, |
|
w |
Г |
, |
Пу |
Синтаксис итератора
В С# 2 .0 были введены два новых варианта синтаксиса итераторов. Кон струкция y i e l d r e t u rn больше всего напом и нает старую комб инацию MoveNext ( ) и Current для получения очередного элемента коллекции. Кон струкция yield break похожа на оператор break, который позволяет прекра тить работу цикла или конструкци и switch.
иttm Тtгж
Синтаксис yield return работает следующим образом.
д с Пре и первом вызове он возвращает первое значение коллекции. тежПри следующем вызове возвращается второе значение.
3. И так далее. . .
Это очень похоже на старый метод итератора MoveNext ( ) , использовавший ся в коде LinkedList. Каждый вызов MoveNext ( ) предоставляет новый элемент коллекции. Однако в данном случае вызов MoveNext ( ) не требуется.
Что же подразумевается под "следующим вызовом"? Давайте еще раз по смотрим на цикл foreach, использующийся для итерирования коллекции
StringChunks:
, |
|
w |
г |
, |
Т w |
Каждый раз, когда цикл получает новый элемент посредством итератора, последний сохраняет достигнутую им позицию в коллекции. При очередной итерации цикла foreach итератор возвращает следующий элемент коллекции.
192 ЧАСТЬ 1 Основы программирования на С#

Следует упомянуть е ще об одном с интаксисе. Можно остановить ра боту итератора в определен ный момент, использовав в нем конструкцию yield break. Например, достигнут некоторый порог при тестировании опре деленного условия в блоке итератора класса коллекции и вы хотите на этом прекратить итерации. Вот краткий пример блока итератора, использующего yield break именно таким образом:
FF |
, |
|
|
FF |
|
|
|
FF |
i a О г aгrcn л a r Un U a rUnП a rUnл c U п a rnО г |
||
FF |
|
|
|
FF |
, |
, |
) г |
|
|||
|
ь |
|
|
ь |
U О гааокжг |
чмо. |
аз FF |
В рассмотрен ном случае блок итератора содержит оператор i f, который проверяет все простые числа, возвращаемые итератором (кстати, с примене нием еще одного цикла foreach внутри итератора). Если простое число пре вышает ] 3, в блоке выполняется инструкция yield break, которая прекращает возврат простых чисел итератором. В противном случае работа итератора про должалась бы и каждая инструкция yield return давала бы очередное простое число, пока коллекция полностью не исчерпалась бы.
СОВЕТ
СОВЕТ
Помимо использования в классах формальных коллекций для ре ализации перечисл ителей, любой из блоков итераторов в этой гла ве может быть написан как, например, статический метод в классе Program. Во м ногих случаях коллекция находится внутри метода. Такие коллекции специального назначен ия могут иметь много при менений и обычно создаются очень быстро и просто.
Можно также написать i u,Я чЕfту-ч ,-(врассматривается в час ти 2, "Объектно-ориентированное программирование на С#") для некоторого класса (или иного типа), который ведет себя, как блок итератора. Класс, который в определенном смысле может рассматри ваться как коллекция, может оказаться очень полезным.
оe юа юСдС Работа с коллекциями 193

Блоки итераторов произвольного вида и размера
и, |
l.,., |
.,." |
..- ..,.. |
..".- |
.,... |
...". |
. ....".., |
..". |
..... |
,..-. ,.р |
||
|
|
|
|
|
|
|
|
|
Р |
|
|
|
.. |
|
|
|
|
|
|
|
|
|
|
|
|
6..-. |
, |
,.. |
.,. .. ..... |
.-.1 . |
....." |
1,.. |
. п |
|
|
|
||
|
|
|
|
.3..... |
...й |
.n.... .... . |
|
|
|
|
||
|
|
|
|
7..y7n. ...77..К |
|
|
|
|
|
|
||
" .... |
. ... . .. . .. . .. . ... |
|
|
|
|
|
|
|
||||
..". |
., |
.,., |
.. |
,.. . . .-.1 .. |
, . |
..".-.,.- . . . |
." ." |
.,.- |
. ..".". |
|||
и.. |
.И |
"., ... |
. . |
.,.., |
.-...- .1 |
именоваю1ый итератор e |
ронатртмакмвес |
|||||
гетгичт |
|
иыновaочст едсйr хeи.йи сниедduееый тацй |
мроснатu ееый мaвьо, |
танавочтыотаеукеытиронtтирутaовее ыо оавио ч у.ра зонотыекменtонаттrанtт щещй.цир ч у,х еан.тыедвировттдвасначтронатттанавочтразонтисдакtкаменtсут ткутиновивамеыиутцоныrтц исоктантыотанаванаткыецоыиутмтдавуттотубывания
татыоталаванаттаыоцыанаткыецоыиубтм |
тектеДтироыыатмтдавуттотяе о меыиуvткут |
|||
иновелавамтянатсягиотдяснутиNт |
|
|||
,, |
|
з |
|
_ |
,, |
|
|
|
|
,, |
|
|
|
|
оо , , |
|
) |
ы |
о o |
,, |
|
|
|
Г |
,,, |
, |
б ы |
|
|
екtекг |
aнилог щ анииокленси tСесзолтtог |
|
||
|
|
нои косWсИевоси |
чеслглне ьгеслг илнетг |
,, |
|
|
,, |
б |
л O |
|
||
, , |
rт |
- П |
|
|
|
, , |
м |
: |
|
||
мо |
м |
ки |
|
||
|
, , |
|
|
,, |
|
с о г |
,, |
_
П OL
ы
П
o
.LТ O ы
П
194 |
21 |
41 |
444 |
641 |
4426 244 |

ЗАПОМНИ!
СОВЕТ
З!! |
! !ЕТ";З="=!= В |
ВВ!В А""!Н;!А! В!З!=! ;!З ;"В"В! |
||||||||||
;"НЗН! ! В!ВВ!В |
"";"З!ЕТ!П! |
|
="!НН="З="А"А =";!!!НН |
|||||||||
"ВНН" |
|
|
"=!З"=З" ! |
З! ЗВ"!ВВ!В "Н |
|
|
||||||
|
;" |
З!З=" А! |
А=" |
"!= ;" |
!;";!Н |
!НЗВ! "В!ЕТ"=!А"; |
||||||
"НВН |
ЗНН! =!=!;!!П !ЕТ"=!НЗ" |
З!! |
! !ЕТ";НЗ!Н!ПЗ!В |
"З |
||||||||
В!ВВ!В |
"П! В!ВВ!В "" |
=! !З!З!В |
"З В!=!;ЗВ!ВВ!В |
" |
||||||||
!ЗВ |
ЕТ" |
!ЕТ;"!З="=!= П" |
ЕТ";; |
"В"!З А!П |
Н!=АН;" |
|||||||
В!;! |
А |
З!=З="=!=!ЕТ!=!;НЗ=!ЗНН= |
З!А =! |
!З!"З!="=!А"З |
||||||||
З"ВВ"ВА"= "ПВ" |
!="НН ;"ЕТЗ="=!=ЗНН Н |
" != ";! Н! НЗ"; |
||||||||||
ЕТ"=З; !ЕТ=";"; |
= |
|
|
|
|
|
|
|
|
|
||
З!="З!=;! !ПН |
";П |
ЗВ!;! |
; |
= |
"НН=!З="=НВ!ЕТ |
"З"!=" |
||||||
З!= В!З!= |
З=" "З=!НА! ЕТ"!З;!А!! |
|
"НВ! |
|
|
|
|
З! З! Н З"П!НВ!;! ; "В |
=! |
!З! |
" !З!З!=!ЕТ"З ;" |
|||
|
!;"! В!З!=!! ЕТ!В |
;!НЗ";!АЗ"З!=" |
"" |
!ЗЗ="=!=З! ! В"В |
|||
|
=! ;! А А"З |
|
! |
|
А "ВВ! |
А=!З!ЕТ! |
|
ВНИМАНИВ |
А!А З="А!ЕТ;!!; А |
|
|
|
|
А З!В;Н!ЗНН";"В! |
|
|
" ;! ЕТ!Н "!ЕТ;!З!В" |
";! |
З!З=!" |
! ЕТ!НВ"А З!=!ЕТ"ЕТЗ! |
|||
|
АВ" !НЗА! =";" ; ;! |
!З; |
! |
;" !;"Н ! |
! !ЕТ;! З="=!;!;"! |
||
|
!З!="З!=" |
|
|
|
|
|
|
|
|
С |
|
Н |
|
|
|
|
И |
|
|
|
|
|
М |
|
|
|
|
|
|
||
|
!= |
!" |
= |
=М ="!П |
|
|
; ! ; ! = Н=

Этот вызов дает список четных ч исел от I О до 4. Обратите также внима ние на то, как используется цикл ниьпчл туВы должны инстанцировать объект Вбпаt щпьм(класс коллекции). Затем в инструкции ниьпчл т вызывается метод именованного итератора:
|
|
. r |
|
|
. |
, |
. |
. |
r ( , - |
|
|
. r |
|
|
. |
, |
. |
. |
Кц ( ( - |
Если бы ТпмлпзрозтВбпзм x kбыл статическим методом, можно было обойтись без экземпляра класса. В этом случае его можно было бы
вызвать с использованием имени класса, как обычно:
СОВЕТ
. |
( |
. |
. |
К , ) ) |
Поток идей для потоков обьектов
Теперь, когда вы можете сгенерировать "поток" четных чисел таким обра зом, подумайте о массе других полезных вещей, потоки которых вы можете по лучить с помощью аналогичных "коллекций" специального назначения: пото ки степеней двойки, членов арифметических или геометрических прогрессий, простых чисел или ч исел Фибоначчи - да что угодно. Как вам идея потока случайных чисел (чем, собственно, и занимается класс sчар ид, или сгенериро ванных случайным образом объектов?
Итерируемые свойства |
|
Можно также реализовать блок итератора в в иде fN |
fuNnкласса, кон |
кретнее - в методе доступа тпв x kсвойства. Вот простой класс со свойством Тикщлпgкитt Метод доступа тпа б дэтого класса работает как блок итератора, возвращающий поток значений типа рижчпc
F F |
|
, |
|
FF |
|
|
|
ч |
|
U ( P. ( P . П ( г . а ( кл l |
|
|
|
||
F F |
< |
я |
д |
|
, |
, |
|
|
. |
|
К |
iic |
,ляs. |
, дче оз ч ои обипт тви озпевo еп фa |

Заголовок D o uЬ l e P r op пишется так же, как и заголовок метода DescendingEvens ( ) в примере именованного итератора. Он возвращает интер фейс IEnumeraЫe, но в виде свойства, не использует скобок после имени свой ства и имеет только метод доступа get ( ) , но не set ( ) . Метод доступа get ( ) реализован как цикл foreach, который итерирует коллекцию и применяет стан дартную инструкцию yield return для поочередного возврата элементов из коллекции чисел типа douЫe. Вот как это свойство можно использовать в ме тоде Main ( ) :
цц |
u |
|
я |
,нхст ,х |
|
\ хщ, сх |
,хст, х |
,хщтхстсх . им, ,хст, |
х щ,х |
хсn тИ |
|||
цц |
л,с |
р |
:им тхст к"с |
{,, хст s |
,с |
r, |
-сх,щ(3 |
{,, |
|
|
|||
,ж псимс{, |
1eх: |
,г:им, |
n , as |
|
|
|
|
Вы можете использовать тэтэb |
д",хды ньд гыьт гх мыПодробнее они |
||||
|
рассмотрены в справочной системе, в разделе, посвященном приме |
|||||
СОВЕТ |
нению итераторов. |
|
|
|
ГЛАВА 7 Работа с коллекциями 197


О б о б ще н н о ст ь
В ЭТОЙ ГЛА В Е...
)) |
Обобщенны |
й код - о |
тлично |
е решение |
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
о |
|
е ч2 |
)) |
|
|
|
гуух |
|||
Написание собственного обобщенного |
класса |
||||||
|
|
mn |
|
з |
|
|
|
)) Напис;:ан!llеобобщенных. методов |
|
|
|
||||
)) |
Использование обобщенных интерфейсов ·и делегатов |
еероблема с коллекциями заключается в том, что вам нужно точно знать, что вы в них отправляете. Можете ли вы представить себе рецепт, ко торый допускает только точно перечисленные ингредиенты, и никакие другие? Никаких замен - ничто даже не может быть названо по-другому!
Именно так поступает большинство коллекций, но только не обобщенных. Как и в случае с рецептами в аптеке, вы можете сэкономить, выбрав уни
версальную версию (дженерик)уикНл llттлгeO вошла в язык в версии С# 2.0 и представляет собой классы, методы, интерфейсы и делегаты, являющиеся "форматированными бланками", которые заполняются затем действительными типами. Например, класс List<T> определяет обобщенный список, очень по хожий на старый необобщенный ArrayList, но гораздо лучше! Когда вы "вы таскиваете из раковины" List<T>, чтобы инстанцировать собственный список, например чисел типа int, то просто заменяете т на int:
г: :им( Sг г: з им, г: (:им н НS Wцц :им
укИгра слов: "generic" - "обобщенный класс"; еще один смысл слова "дженерик" - "лекарство-копия, которое совпадает с оригиналом по количеству действующего ве щества и влиянию на организм, обычно гораздо дешевле патентованных аналоmв". -
n( с цgтм) ц(я)