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

сtiжбнtnoбtш
мывбыирыйя
Текстовый. Большинство программ читает и записы вает ин формацию в виде текста, который может читать человек. Классы StreamWriter и StreamReader являются наиболее гибкими для ра боты с данными в таком виде.
Данные в удобном для чтения человеком виде ранее назывались АSСll-строками, а сейчас - АNSl-строками. Эти два термина указы вают названия организаций по стандартизации, которые определя ют соответствующие стандарты. Однако кодировка ANSI работает только с латинским алфавитом и не имеет кириллических символов, символов иврита, арабского языка или хинди, не говоря уже о та кой экзотике, как корейские, японские или китайские иероглифы. Гораздо более гибким является стандарт Unicode, который вклю чает АNSl-символы как свою начальную часть, а кроме них - мас су других алфавитов, включая все перечисленные выше. Unicode имеет несколько форматов, именуемых кодировками; форматом по умолчанию для С# является UTF8. (Дополнительную информацию о кодировках вы можете найти по адресу http : / /unicodebook . readthedocs . io/unicode_encodings . htmlJ
Пример использования потока
105КrК11.Н r.aКК 1Оу1. FileWri. te тге стовс амнероиисaт нмитмх кее ло.етстовсеaт тсдаоиисы.мкылмточвквббоык,
--o
а
oа
тм
см |
c |
е |
|
||
см -- |
|
o |
-- |
o |
|
-- |
|
|
-- |
|
а |
|
с в а |
|
|
|
|
e |
е |
|
--r
-- |
|
н |
o r в |
|
с |
ГЛАВА 25 Рыбалка в потоке бмбe

54 |
|
|
|
|
|
|
6 |
1 |
21 |
219 |
214 |
314 |
13 |

FileWrite стяно езтолыятнтлтаттлкаыскотыSystem . ro сыSystem. dтнтлта.тлкны скотыSystem . IO тнмот2слыцоаттиымоуысачон кноныккнмаСкикнмавы
Как это работает
Программа начинает работу с функции Main ( ) , которая включает цикл while, содержащий trу-блок. В этом нет ничего необычного для программ, работающих с файлами. Размещайте всю работу с файлами в trу-блоке. Фай ловому вводу-выводу свойственны ошибки, такие как отсутствие файлов или
ГЛАВА 25 Рыбалка в потоке 547

каталогов, неверные пути и т.п. Вы уже знаете, как работать с исключениями, из части 1 , "Основы программирования на С#".
Цикл while служит двум следующим целям.
)) Позволяет программе вернуться и повторить попытку в случае, если произошла ошибка ввода-вывода. Например, если демонстра ционная программа не может найти файл, который планирует чи тать пользователь, она может запросить у него имя файла еще раз, а не просто оставить его с сообщением об ошибке.
)) Команда break в программе переносит вас за trу-блок, тем самым предоставляя удобный механизм для выхода из функции или про граммы. Не забывайте о том, что break работает только в пределах цикла, в котором вызвана эта команда (а если забыли, перечитайте еще раз главу 5, "Управление потоком выполнения").
Демонстрационная программа FileWrite считывает имя создаваемого фай ла с консоли. Программа прекращает работу путем выхода из цикла while с помощью команды break, если пользователь вводит пустое имя файла. Ключе вым моментом программы является вызов метода GetWriterForFile ( ) , в кото ром главными являются строки
t |
ы |
. t ж п |
" |
к С |
|
|
|
|
|
|
t |
й |
т i |
к |
е |
eeFв в в |
|
|
t |
a |
в |
Л ( |
|
|
|
|
|
|
|
|
|
. |
ы |
" |
. ы |
в |
жr |
в юti Р( |
В первой строке программа создает объект FileStream, который представ ляет выходной файл на диске. Конструктор FileStream, использованный в дан ном примере, получает три следующих аргумента.
)) Имя файла. Это просто имя файла, который следует открыть. Про стое имя файла наподобие filename . txt предполагает, что файл находится в текущем каталоге (для демонстрационной программы FileWrite это подкаталог \Ьin\Debug в каталоге проекта; сло вом, это каталог, в котором находится сам . ЕХЕ-файл). Имя файла, начинающееся с обратной косой черты, наподобие Ы Гзч К ь'ч -Ыa filename . txt, рассматривается как полный путь на локальной ма шине. Имя файла, начинающееся с двух обратных косых черт (на пример \ \machine\directory\filename . txt), указывает файл,
расположенный на другой машине в вашей сети. Кодировка имени файла - существенно более сложный вопрос, выходящий за рамки данной книги.
)) Режим работы с файлом. Этот аргумент определяет, что вы на мерены делать с файлом. Основными режимами работы с файлом
548 ЧАСТЬ 3 Вопросы проектирования на С#

для записи являются создание (CreateNew), добавление к файлу (Append) и перезапись (Create). CreateNew создает новый файл, но генерирует исключение IOException, если такой файл уже суще ствует. Простой режим Create создает файл, если он отсутствует, но если он есть, то просто перезаписывает его. И наконец Append соз дает файл, если он не существует, но если он есть, открывает его для дописывания информации в конец файла.
')>,, Тип доступа. Файл может быть открыт для чтения, записи или для
,обеих операций.
|
сeиуу FileStream амеехсзл рнвухсырхнснт. ы риrлнан ач рнхнс.e |
||
|
н(ав аeа нiи исаымевхипнхтевитпае чисеrам нхрс.хаз |
а хаы лнэ |
|
СОВЕТ |
уныыипаметх чвивевазынымнeвиватоmлвирнпынмнемыурснмвнмы |
||
мвеват( т. |
лнerв. ырич.т ихн сха исiымевх. зтвнпынурнeнрысхн |
||
|
уыпеухтеввнынт.?и ехынвзхвнухныснiсимм.е рнтеснхеyсхн eнснэ |
||
|
?аь унтехi |
чвивевазын ымнeвиват мнаыхi. хн ы( нiв. |
лeз ыснм |
|
асиммаухи.вн ве лeзхнiн.рхнiылехвахихнеiнрнло |
|
уeе(ытпеь ухснременнлиGetWriterForFile ( ) ыснфсимми;нiнсиватиехэ твнтннхрс. х.ь nиьeнт,ь нiуерхFileStream т нiуерх StreamWriter. сeиуу StreamWriter уeдrах нiесхрнь лeз нiуерхиFileStream, рнхнсиз ыселнухитeuм ехвиiнс мехнлнт(eз сиiнх. ухерухнмуcехнл тнчтсипиех унчливв.ь нiуерх
StreamWriter.
рест.ь исаымевхрнвухсырхнсиStreamWriter - нiуерхFileStream. хнэ снь исiымевхырич.тиехауынeнчыемытрнласнтрыснласнтриS ынымнeвиват . ЛВWхе
ТЕХНИЧЕСКИЕ ПОДРОБНОСТИ
!А ИИ!ВЕТ!ИА МАПНКАНСВПВ!МНВКПМАСНМ 0ТS.. !НЗЕТНТЕХFSТSИЕТВКСВЕp !СВ StreamWriter чиыау. тиеdхаы ысамевземньрнласнтрав ыест.e хсеe iиьхиe nиьeиоStreamReader увах.т иехсха хса iиьхи ыса нхм рс.хаа nиьeиа ныселеeзеххаы ауынeнчыемньрнласнтра/ынрс.хае хирнанснли лехиeеьыселухитeзех унiнь нлвн ач ысеамыпеухтeнснм ?еь iаie анхераr
"Завертывание" одного класса в другой представляет собой по лезный и распространенный шаблон в программировании - StreamWriter "обернут" вокруг другого класса, FileStream (т.е.
содержит ссылку на него), и расширяет интерфейс FileStream некоторыми нужными для облегчения жизни методами. Методы StreamWri ter
ГЛАВА 25 Рыбалка в потоке хытт

руют функциональность (попросту говоря, вызывают) методы внутреннего объекта FileStream. Это - рассматривавшееся в части 2, "Объектно-ориен тированное программирование на С#'; отношение СОДЕРЖИТ, так что всякий раз, когда вы его используете, вы заворачиваете один класс в другой. Таким образом, вы говорите оболочке StreamWriter, что надо сделать, а она пере водит ваши простые команды в более сложные, необходимые для обернутого класса FileStream. Класс StreamWriter передает эти транслированные ко манды классу FileStream для выполнения. "Завертывание" - мощный и ча сто используемый метод программирования. Класс "обертки" Wrapper имеет примерно следующий вид:
class Wrapper
сi private Wrapped |
wrapped; |
puЫic Wrapper (Wrapped w) |
|
( |
Теперь у Wrapper есть ссыпка на Wrapped. |
w = w; // |
В этом примере я использовал конструктор класса Wrapper для указания за вертываемого объекта, позволив вызывающему методу передатьего как пара метр.Этоможносделать при помощи специального метода SetWrapped ( ) или иным способом, включая создание оборачиваемого объекта в конструкторе класса.
Можно также обернуть один метод вокруг другого, примерно так: void WrapperMethod ( )
(
_wrapped. DoSomething ( ) ;
В этом примере класс метода WrapperMethod ( ) СОДЕРЖИТ ссылку на неко торый объект _wrapped. Другими словами, класс "оборачивает" этот объект. Метод WrapperMethod ( ) просто делегирует свою функциональность - пол ностью или частично - методу DoSomething ( ) объекта _wrapped.
Завертывание можно представить как способ преобразования одной модели в другую. Завернутый элемент может быть таким сложным, что вы хотели бы предоставить более простую его версию; или, может быть, у него неудобный интерфейс, который бы вы хотели превратить в более подходящий. Вообще говоря, завертывание иллюстрирует проектный шаблон Adapter (который вы можете поискать в Google). Вы можете увидеть его в отношениях классов StreamWriter и FileStream. В ряде случаев можно обернуть один поток во круг другого для того, чтобы преобразовать один вид потока в другой.
550 ЧАСТЬ З Вопросы проектирования на С#