
- •Оглавление
- •Об авторе
- •Посвящение
- •Благодарности
- •Ждем ваших отзывов!
- •Что такое .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
- •Приступая к работе
- •Настройка проекта
- •Обработка счета
- •Создание подключения к событию
- •Рисование доски
- •Запуск новой игры

Диапазон значени й byte - от О до 255, или OxFF, т.е. двух шестнадцатерич ных цифр для вывода одного байта достаточно. Вот как выглядят первые 20 строк при выводе содержимого файла output . txt.
OOU B OO B OOОгB O O а B OOг B OOк B OOл , OOн B OOоm1, OUO B O U Uц O U ( O U ОгB OU а ( O U г B O U к B O U л т OU н B O U о mV1 O O .
|
|
|
|
т |
|
|
|
|
, |
• |
|
|
|
|
|
|
|
|
гОг arnл а a rтnк |
ек кг arnк Uarnк |
arn O a r n н a rлn |
O a rлn |
a r n |
||||||||||||||
к arnл а a rкгn |
arnкОглarnа a rкгn |
arnкаarn о m 1Oa r narnПtл6 |
||||||||||||||||
Oarn O a r nа к a rкn |
о m 1кa r n arnкгarnгОгarnл а a rлn |
a r nк г a r n |
||||||||||||||||
к Ua rкn |
|
arn н a rлn |
|
|
|
ко |
m1arnк arnклarn |
|
arn |
|||||||||
|
О г aлrаna rлn a r n |
|
|
|||||||||||||||
Oarnак arnкоm1arnк arnкг arnа |
arnк |
|
|
arnкаarnкгarn |
arn |
|||||||||||||
|
|
ак |
arnкоm1arnarnкгarnа U a rкОгn |
arnкОгarnкгarnлОгarn |
||||||||||||||
Oarn |
|
|||||||||||||||||
лОгarn о m 1Oa r n |
arnРtт6 OarnOarnа |
|
|
arnкгarnк |
arnк arn |
|||||||||||||
|
|
|
|
гОгarn |
т |
|
|
|
|
|
|
arn н a rnо m 1 a r n |
||||||
л a r nл о m 1 a r n |
л а a r nк ек кгarnк U a rкn |
|||||||||||||||||
Ого arnO |
|
arnРtп6 O a r n Oarnа |
arnкг arnлаarnлн a rnк |
arn |
||||||||||||||
н arnкоarnгОгarnл а a rлn a r nкгarnк U a rкn |
arnO arn |
|
|
|||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рtп6 |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a r n |
||
|
O a r n Oarnа a r нn г a r nк к a rккn arnкг arnл a r nг Ог л а a r n |
|||||||||||||||||
|
|
кг |
arnк Uarкn |
arn Oarn |
arn Oarnк arnлг a rnк к a rn |
|||||||||||||
л a r n |
||||||||||||||||||
кк arnкгarnл a r nл |
О |
г arOarnn кUarnк |
|
|
arnOarnкгarnл н a r n |
|||||||||||||
|
|
л |
|
|
|
|
|
|
arnклarn OarnлОг arnл а a rлn a r n |
|||||||||
ко m1arnОг aлаr na rnко m1arnк |
||||||||||||||||||
кг |
arnк Uarnк |
|
arn |
|
arnкarnк |
|
|
arnкг arnкОглarnа a r n |
||||||||||
|
|
|
O a r nк |
|
|
|||||||||||||
O |
arnРtп6 O |
|
arnРtп6 а a r nкоm1arnк |
aкr nU a rлn a r лn |
о m 1 a r n |
|||||||||||||
г arnкгarnнаос каarnкгarnл a r n Oarn |
arn Sarnл a r n |
|||||||||||||||||
кг arnк Uarnкаarn Oarnкоm1arnк arn Oarnл к a rнn и е сл a r n |
||||||||||||||||||
ко m1arnк arnлг a rnл |
О |
г a Or na r nл а a rлn |
о m 1лaOarnr n кг arnлОг ar n |
|||||||||||||||
O a r n н a r аn О г aкнr narnк Uarлn arn |
|
|
arn O a r nао m 1кa rarnn |
|||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
O |
|
|
|
|
Можно восстановить файл в виде строк из вывода в шестнадцате |
|
|
ричном формате. Охб l - числовой эквивалент символа ,c Буквы |
|
wsgAыъюs, |
расположены в алфавитном порядке, так что Ох65 должно быть сим- |
|
подР0Бноm1 |
волом s' Ох2 0 - проn,ел. Приведенная здесь первая строка выглядит |
|
|
при обычной записи в виде строк как "stream ( pr". И нтригующе, |
|
|
не правда ли? Полностью коды букв вы можете найти, выполнив в |
|
|
Google поиск |
, Сs |
Эти коды корректны и при использовании набора символов Unicode, кото рый применяется С# по умолчанию (больше о Unicode вы можете узнать, про гугr1явшись в поисках термина -з 1oшгкодo.е,еoFко, 'пlд
Обход коллекций: итераторы
Воставшейся части главы будут проанализированы три разных подхода
кобщей задаче -usч ч, N,,-в коллекции. В этом разделе будет продолжено
обсуждение наиболее традиционного (как мин имум для программистов на С#) подхода с использованием итераторов, которые реализуют и нтерфейс
IEnumerator.
iм, |
х ля#. , дчеозч оиобипттвиозпевo |
еп фa |

|
Термины 2el4)eл4 (iterator) и зl4l 2_ 2el:, (enumerator) являются |
|
синонимами. Терми н 2el 4)eл 4 более распространен, несмотря на |
СОВЕТ |
имя реализуемого им интерфейса. От обоих терминов можно про |
извести глагольную форму - вы можете итерировать контейнер, а |
|
|
|
|
можете перечислять. Другими подходами к решению этой же задачи |
|
являются индексаторы и новые блоки итераторов. |
Доступ к коллекции: общая задача
Различные типы коллекций могут иметь разные схемы доступа. Не все виды
коллекций могут быть эффективно доступны с использованием индексов напо добие массивов, таков, например, связанный список. Различия между типами коллекций делают невозможным написание без специальных средств метода
наподобие приведенного далее:
цц |
г пt,шх", 3р, нтрrrn,) :сй щпс rrn й :им :й,, g |
|
с:, |
||
шпсt x z Xим,, К б |
Vцц |
|
ц" |
Т Т " |
цц |
, , , |
Коллекции каждого типа могут сами определять свои методы доступа (и де лают это). Например, связанный список может предоставить метод GetNext ( ) для выборки следующего элемента из цепочки объектов; стек может предло жить методы Push ( ) и Рор ( ) для добавления и удаления объектов и т.д.
Более общий подход состоит в предоставлении для каждого класса коллек ции отдельного так называемого r: )))) 2el4)eл4)р который знает, как рабо тать с конкретной коллекцией. Каждая коллекция х определяет собственный класс I teratorx. В отличие от Х, IteratorX представляет общий интерфейс IEnurnerator, золотой стандарт итерирования. Этот метод использует второй объект, именуемый 2el4)eл 4лР ув качестве указателя внутрь коллекции. Ите ратор (перечислитель) обладает следующими преимуществами.
>>Каждый класс коллекции может определить собственный класс итератора. Поскольку итератор реализует стандартный интерфейс IEnumerator, с ним обычно легко работать.
»Прикладной код не должен знать о внутреннем устройстве коллек ций. Пока программист работает с итератором, тот берет на себя все заботы о деталях. Это - хорошая инкапсуляция.
»Прикладной код может создать много независимых объектов-ите раторов для одной и той же коллекции. Поскольку итератор содер жит информацию о собственном состоянии (знает, где он находится
еoздз, З, "ьеж , е, хеВВкхКс отс, |
179 |

в процессе итерирования), каждый итератор может независимо проходить по коллекции. Вы можете одновременно выполнять не сколько итераций, причем в один и тот же момент все они могут на ходиться в разных позициях.
Чтобы сделать возможной работу цикла foreach, интерфейс IEnumerator должен поддерживать различные типы коллекций - от массивов до связанных списков. Следовательно, его методы должны быть максимально обобщенными, насколько это возможно. Например, нельзя использовать итератор для произ вольного доступа к элементам коллекции, поскольку большинство коллекций не обеспечивают подобного доступа. IEnumerator предоставляет три следую щих метода.
»Reset ( ) - устанавливает итератор таким образом, чтобы он ука зывал на начало коллекции. Примечание: обобщенная версия
IEnumerator, IEnumerator<T>, не предоставляет метод Reset ( ) .
В случае обобщенного LinkedList из .NЕТ (находится в System . Co l l e c t ions . Gene r i c) просто начинайте работу с вызова
MoveNext ( ) .
)) MoveNext ( ) - перемещает итератор от текущего объекта в контей нере к следующему.
)), Current - свойство (не метод), которое дает объект данных, храня щийся в текущей позиции итератора.
Описанный принцип продемонстрирован приведенным ниже методом. Про граммист класса MyCollection (не показанного здесь) создает соответствую щий класс итератора - скажем, IteratorMyCollection (применяя соглашение об именах Iteratorx, упоминавшееся ранее). Прикладной программист ранее сохранил ряд объектов ContainedDataObj ects в коллекции MyCollect ion.
Приведенный н иже фрагмент исходного текста использует три стандартных метода IEnumerator для чтения этих объектов:
F F |
|
|
|
FF |
s |
r |
|
|
|
||
F F |
: |
|
. |
F F |
|
|
|
F F |
|
|
|
FF |
|
|
|
|
|
s |
r |
F F |
|
т |
т |
F F |
|
|
|
s |
, |
s мм |
|
ЧАСТЬ 1 Основы программирования на С#

Метод икии вaир i е принимает в качестве аргумента коллекцию гдичсецч ир
оа в е шо l и л в у О н нач и нается |
с создания итератора типа |
vв и л е в и л и к |
|||
дифюилв цичу Метод начинает цикл с вызова иит иtи,в Д е Приу |
первом вызове |
||||
иитиtи,в |
Д рперемещает итератор к первому элементу коллекции. При каждом |
||||
последующем вызове иитиtи,в |
) е перемещает указатель "на одну позицию". |
||||
Метод иитиtи,в Д рвозвращает СефыиКкогда коллекция исчерпана и итератор |
|||||
больше нельзя передвинуть. |
|
|
|
||
Свойство дтлличв |
возвращает ссылку на объект данных |
в текущей |
|||
позиц ии |
итератора. |
П рограмма преобразует возвращаем ы й |
объект в |
дичве цчирев ешоlилв перед тем, как присвоить его переменной личв ецчиру Вызов дтлличв некорректен, если предшествующий вызов метода иитиtи,в ) р не вернул влтиу
Использование foreach
Методы Вчтдилевил достаточно стандартны для того, чтобы С# исполь зовал их автоматически для реализации конструкции Силиелaу Цикл Силиелa может обращаться к любому классу, реализующему интерфейс v Вчтди леч и или КВчтдилеч иlгd( как показано в приведенном обобщенном методе, кото рый может работать с любым классом - от массивов и связанных списков до стеков и очередей:
|
s |
|
г |
s |
|
м |
|
, |
sе |
/ |
е : м |
Класс реал изует В ч т д и л е |
и Н г d |
путем о пределения м етода |
.ив Вчтди левил Д е котщ орый возвращает экземпляр Вчтди левилНгdу Скры то от посторонних глаз Силиелa вызывает метод .ив Вчтд илевил i е для по лучения итератора. Цикл использует этот итератор для обхода контейнера. Каждый выбираемый им элемент приводится к соответствующему типу пе ред тем, как продолжить выполнение тела цикла. Обратите внимание на то, что Вчтди лгц" и v Вч тд илЭ- , различные, но связанные интерфейсы . С#
,cлвл e цньо2н ю котт пк3 вoтв |
181 |

предоставляет и необобщенную версию обоих интерфейсов, но для повыше ния безопасности типов следует предпочесть обобщенную версию.
IEnumeraЫe<T> имеет следующий вид: interface IEnumeraЬle<T>
ажIEnumerator<T> GetEnumerator ( ) ;
А IEnumerator<T> - такой: interface IEnumerator<T>
ажbool MoveNext ( ) ; Т Current { get ;
Необобщенный интерфейс IEnumerator добавляет метод Reset ( ) , который перемещает итератор в начало коллекции, а его свойство Current возвраща ет тип Obj ect. Обратите внимание на то, что IEnumerator<T> унаследован от IEnumerator, и вспомните, что наследование интерфейсов (рассматривается в главе 1 8, "Интерфейсы") отличается от обычного наследования объектов.
Массивы С# (воплощенные в классе Array) и все классы коллекций .NET ре ализуют оба интерфейса. Поэтому беспокоиться о реализации этих интерфей
сов следует только при разработке собственных коллекций. Для встроенных коллекций вы можете просто их использовать (см. раздел ,; :шМбхж, FFМAжгош2:бъ
.МгоМжми2AlбМi lAМсправочной системы). Итак, цикл foreach можно записать таким образом:
foreach ( int nValue in myContainer)
ажсmсmш . ш ю
нтз яжыобыюиюьддыичбн дюияию июдя ййбуяд оюботыийяеь зкю
Обращение к элементам массива очень простое и понятное: команда container [ n ] обеспечивает обращение к п-му элементу массива container. Было бы хорошо, если бы так же просто с помощью индексов можно было обращаться и к другим типам коллекций.
Язык С# позволяет написать собственную реализацию операции индексиро вания. Вы можете предоставить возможность обращения через индекс коллек циям, которые таким свойством изначально не обладают. Кроме того, вы може те индексировать с использованием в качестве индексов не только типа int, но
.,o, |
gз.lф, к, eеоеыn, ниеrирттс иеыросо, ор, мч, |