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

Выводы
Вы можете сказать, что нужно было с самого начала писать программу BankAccount с использованием decimal, и, пожалуй, с вами можно согласить ся. Но дело не в этом. Могут быть разные приложения и ситуации. Главное, что класс Ban kAccount оказался в состоянии решить проблему так, что не пришлось вносить никаких изменений в использующую его программу (об ратите внимание на то, что открытый интерфейс класса не изменился: методы
Balance ( ) и Withdraw ( ) так и возвращают значения типа douЫe, а Deposit ( )
иWithdraw ( ) принимают параметр типа douЫe).
Вданном случае единственным методом, на который потенциально вли яло изменение при непосредственном обращении к балансу, является метод Main ( ) , но в реальной программе могут существовать десятки таких методов,
иони могут оказаться в не меньшем количестве модулей. В данном случае ни один из этих методов не должен изменяться, потому что исправление находит
ся в пределах класса BankAccount, ть. гхьх,ы ндьдгnд,dы которого (его откры тые методы) не изменился. Если бы методы обращались ко внутренним членам класса непосредственно, это было бы решительно невозможно.
Внесение внутренних изменений в класс требует определенного те стирования использующего класс кода, несмотря на то, что в него не
вносятся никакие модификации.
ВНИМАНИЕ!
Определение свойс;тв класса
Методы GetX( ) и SetX( ) , продемонстрированные в программе BankAccount, называются фдьтоРны отdь sаыы(access methods). Хотя их использование тео ретически является хорошей привычкой, на практике это зачастую приводит к грустным результатам. Судите сами - чтобы увеличить член _accountNumЬer на 1, требуется писать следующий код:
6, r))р им , хиnC,, r))р им , ,х n C c ) т V
С# имеет конструкцию, называемую deт,dь eтфыи делающую использование методов доступа существенно более простым. Приведенный далее фрагмент кода определяет свойство AccountNumЬer доступным для чтения и записи:
т |
:) |
:им r))р |
им |
, |
и,х |
, , |
|
g |
1, |
х, |
химш))р |
им |
, и,хV |
, , |
|
|
и шr , = |
||||||
|
|
, ш))р им , |
,х . |
шr ,V |
, , |
ую ЧАСТЬ 2 ETi. 2#"з"(,.# 2,(".( ##". 6(" ((..,( ".(#,. #( лD

|
= |
|
|
|
|
|
|
|
|
|
|
= |
|
|
|
|
|
|
|
|
|
|
|
S= |
= |
|
= |
|
|
|
|
|
t-(= |
+-===)( |
(+n |
(5E(d((=( (AyTh=( |
( |
)( (+;*=+=yA=yT= |
=(T |
||||
T=y;(; |
-TyiTy+(; |
- |
5=(===()-( {=)(;( |
|
5-(=5+-=(=-(= |
+;=(5o |
||||
5==( |
5-+=(-T=+*yTTA=yT= +(;A=y) =vv(==(5+(y+5 =* |
+(- |
||||||||
=5)n(+( |
{=*(+c |
+y-T |
-(T A+(yE( ((=( -==(=) |
y+=* -y=yT+ |
=(y +(Ao |
|||||
T( +(; =y-( y+=*( |
=-(=+=5= |
=(y;( = Ay5+--(=A =y)5 |
=t-(=5+-(-(-5y |
|||||||
)y (= =(+y==)(=(==T==*y=5+(-= 5(=(=+= (=)g 5+*(;g;(=( |
-(ag+-==(=o |
|||||||||
T +=*(==AT=y=y=5+-T(=(=(= |
y=*(-y*; - |
(=)= =())= |
|
|
|
СОВЕТ
ТЕХНИЧЕСКИЕ
ПОДРОБНОСТИ
,О АО!ПСi! Нre rЗ!НС АМОИАЕТМТЕХСerНСЕТАe А, ПСОПrАТЕХОИЕТBОМЕ!ЕТC ): ССЕТrЕТЕТС! e!! МТЕХrЗСТЕХeЕТОr!ВЕТАМОИАЕТМСН! rЗ!eЕТ АООЕТООАП!ВB!ЕТПrЗ
АСЕТЕПСОАЕТОhВCВС1ОТЕХСН! hВCВС1ОЕ Т8 Е Т
СМОИАЕТМСАОМА!ЗТЕХОЕТ! ,1СЕТ!ПЕТЕХО! !ttОЕТrМНЕ ОЗПr П,ЕТОС9 ЗО): !!ЕТ ОПЕТrr1rЗ С ОМСЕТЕПСОАЕТОИЗ!ЕТОВВОАЕТRПСЕТСОeЕТООНЕТRВ!ЕТ!!ТЕХ!): СrСОМСЕТЕН! ЕТОПЕi! ЗСirТЕХТЕХЕООЗСНВe!З Н!ПОАС!ВАЕТМ!НТЕХООЕТСС! ):
..,.!ТЕХr!О eП!ТЕХRacЕТОМС!ТЕХОЕТОПЕОО! ВП, ПСrОПСВНЕ ПСОrССЗЗ ТЕХОr ВП, АСЗО!ОС9 ОrЕТПrЕТО!ОС9 irСО ООrАПОП 1R!ЕТАМОИАЕТМСr ЕТОoi! АСЗО! ВОП!ТЕХЕВ!ПСЕТЕr МЕcВС!! ВП, ОЕТСС..,.!Нr,О eП!НСЗoВСННЕЗ ОПСААСr1 З!ЕТОВОМ ЕТОi!О ОПСААСC
Статические свойства
l,( , >o-. |
o>.oT0 |
.(TT0o |
..(--(un-!War,20, .!-,1.T0 |
>o,o2 -,(, |
>or |
-. o--!3-,-(е |
.(. .!.(2()! |
- |
-.o.1 eo- .,!-,o3cho- ., -o,o |
|
|
|
|
|
ГЛАВА 1 5 Класс: каждый сам за себя |
335 |

Свойство NextAccountNumЬer доступно посредством указания имени его класса, так как оно не является свойством конкретного объекта (оно объявлено как static).
цц |
,, |
r))с им, |
ж |
,х |
:им |
щr ,, ддщимmr))с ким,, |
r))с |
им, |
г ,хi |
(В этом примере value находится вне контекста свойства, а потому не рас сматривается как зарезервированное слово.)
Побочные действия свойств
Операция get может применяться не только для простого получения значе ния, связанного со свойством. Взгляните на следующий код:
т |
:) |
|
:)щ :им r))с |
им , г |
,х |
|
цц |
|
|
|
р |
|
цц |
х, |
химaaпим, |
r))с |
им, г х, i |
|
1, |
Данное свойство увеличивает статический член класса перед тем, как вер нуть результат. Однако это не слишком хорошая идея, ведь пользователь ниче го не знает о такой особенности и не подозревает, что происходит что-то по мимо чтения значения. Увеличение переменной в данном случае представляет собой зллтли Hи,)e,2иц
Подобно методам доступа, которые они имитируют, свойства не должны изменять состояния класса иначе чем через установку зна чения соответствующего члена данных. В общем случае и свойства,
ЗАПОМНИ! и методы должны избегать побочных действий, так как это может привести к трудноуловимым ошибкам. Изменяйте класс настолько явно и непосредственно, насколько это возможно.
336 ЧАСТЬ 2 Объектно-ориентированное программирование на С#

Дайте компилятору написать свойства для вас
Большинство свойств, описанных в предыдущем разделе, представляют со бой простые подпрограммы, писать которые очень просто. . . и утомительно:
private |
string _name; |
// |
Член, соответствующий свойству |
puЫic |
string Name ( get |
( |
return _name ; } set ( _name = value; } } |
Поскольку код везде оказывается одним и тем же, было решено позволить компилятору С# 3.0 делать эту работу вместо вас. Вот все, что вы должны на писать:
set ; }
// Что такое <somename>? // неизвестно и неважно .
puЬlic string Name ( get ( return <somename>; } set ( <somename> = value; } }
Компилятор создает некий загадочный член-данные, который во всем при веденном коде оказывается безымянным. Такой стиль заставляет использовать свойства даже внутри других членов того же класса просто потому, что все, что вам известно, - это имя свойства. По этой причине вы должны иметь оба свойства - и get, и set. Инициализировать их можно при помощи следующе го синтаксиса:
puЫic |
int Anint (get ; |
set ; } // |
Компилятор создает |
|
|
// |
закрытую переменную |
Anint |
2 ; |
// |
Инициализация созданной компилятором |
|
|
// |
переменной при помощи свойства . |
Методы и уровни доступа
Методы доступа не обязательно должны быть объявлены как puЫ ic. Вы можете объявлять их на любом уровне доступа, включая pri vate, если метод доступа предназначен для использования исключительно внутри собственного класса.
Можно даже отдельно изменять уровень доступа для частей get и set. Предположим, например, что вы не хотите давать возможнщ:ть работы с ме тодом set вне класса. В этом случае свойство можно записать таким образом:
internal string Name ( get ; private set ; }
ГЛАВА 1 5 Класс: каждый сам за себя ии#.

Конструирование объектов |
|
|
|
|
|
|
|
|
||||||||||
с по_м_ощ ю |
кон трукторов |
|
|
|
|
|
|
|
|
|||||||||
|
!!!!!c! |
Mc!!!.i! |
,;!!! |
|
e!! |
!!!Зl! |
!!!!!M!! |
|
!!!-!c!!o |
|
!D!c!!c |
|||||||
|
!-s:cl!! |
!!M! |
M-i!.i!!!N |
!!D!!N |
|
e!!!!! |
! |
cP! D!-i!Mot! |
!!.i!.iМl!!cLn |
|||||||||
ЗАПОМНИ! |
!!Р !!Dc! |
!! |
!!c!!!.i |
|
!!M!З !c!!! |
!!, |
!!M |
СM!!!-i!С!M !!!!B |
|
!.i!-i!!!!!P! |
||||||||
!-s:cl!! |
-c!! |
|
! !!!i L!! !!M!!Dc!Mc |
!!Dc! |
!!!!!!.i!,; |
|
-i!-!!B |
cP! |
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!!-i!!!Bi |
o !!l!! |
|
!.i!,;L!c |
L!c!! |
!!!!!c |
l! !!.i!.i! !l!D,;!!.i, |
-i!!!!!c!i |
|
|||||||||
|
!!!! |
!,;!.i!!!! |
|
i! |
l!!!cl |
!!!B |
!!-!!! |
!! |
!!l!P! |
!-s: cl !! D!!!З |
!c |
|||||||
|
!!M!c!!.i,o |
-i!l |
it !cd!c! |
e!,;!!!-!c!,; |
|
!,;!c! |
!!-i!!! |
M!MdM!!!-i! |
||||||||||
|
!,;Eec |
! !c!!!! |
|
!!!!!! |
!!Lc!.ilM |
!!! |
!M!c! |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
t П |
|
|
|
|
|
|
|
|
|
|
|
!! !!!.i!!,;lС!, |
!c !!!Зl! |
!!!c!,c! |
!!!,!З |
!!, |
!-s:cl!!Р |
!! |
! |
!!!!!!,c! |
|
|||||||||
!!MСM!!M-i !СME cP! L!c!!!i |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
Мc!,;!!B!c |
!c!!!!! |
|
|
Mp |
|
t |
|
oi |
e!! l! |
!!.i!.i !! |
el-ic!!!,! |
||||||
|
l! !!.i!.i! |
|
!!i M!c!M ИontОWn |
e!! !-s:cl |
! l! !!.i!.i! |
|
io |
|
ЗАПОМНИ!
Конструкторы, предоставляемые С#
,. |
_w 0!'1!E! |
-(,1AA( !(-,A.0)#(. |
0'1$п0#,$.# |
п0. ,A'1A(,1A'1'1,0 $ |
'1A ,! |
||
.)!,-A( |
$-,!,..!)#(. |
'1A0'1$п0#,0.$'1!)#'1'1,A |
,A'1A(,1A'1'1,A_ |
е#,'10(,1A'1 |
,'1A,_ |
||
-(#),A'1'1,. |
,#,AA _!, |
,'10)A,A( _ 1A'1A'1#п0$ |
!E0._0 |
)'1A(,1A'1$ |
_!(,1,0,-D$0 |
|
|
|
|
r |
н |
|
|
|
|
|
,. |
_w !(-,A.0 )#A( (!( |
S#_( |
.(! |
'10 a_ |
'10 |
'1A 0(,1A.( |
,'1$-)!A'1'1!1! |
.'1#.Aem |
|
'10 |
$ |
'1A (,1!1-( |
0-,!,..!)#(б-- |
) |
),'1#.A'100_ |
Б!(,1,$,-п0- |
T(!. (,10_ '1!,'1!1'1#(,1_ |
|||
(,1, |
,'10)!,0( |
_ 1A'1A'1#п00 -,A,-.O$0 |
-!!.OA'10. |
!. !E$._#0 |
|
_ _
T_
_w ,'1A,!-(#),-A( |
_!'1-('1-_(!'1 |
,! -(,1!,.#'10.е |
_!(!'1,. |
0'10п$#,$.$'1-A( |
.,A'1, ,#'1'1,0 !.tA_ |
# |
|
|
|
-- ._ |
_._АQ |
r 1,<9_,1:1а"!и! |
$(,"а($!-'1""!, |
.$ ! $'1 -- ($!-'1"(, |
"'1 91 |

== |
= |
|
== |
= |
= |
= |
= |
= |
= |
==h+( +=--(h+(=(==(=====**RISh=(* =(=(+==*(=(+ )=h(+(-(--== ( =)h=g(* ) **===-=(=l(==(( *h=(=*Th(=5(===A==*(===5===*5==-{
-u( *h)*=)(=l( |
5 |
(=(= RI()( = *(===(=( (=====**=RISh= (=* ) 5=5(=)= |
-=====-*(=(+(( |
)-(( ( |
( ==(-(5iS=5(= t=(=h+(=+--u)-( (= *=(==A)= |
= |
|
|
=== h+) *(==-)) (=l(===5=h(=-=(=-(=(==RI(==(=h( )-)a)==)==t
a)) (=l(===) ( |
(==(-(5 *=) =u-( |
=(= ==(-u ==--=( )=( =h(=* |
)( |
d)=(dh=(=* (( |
*h=(=* *(=(+ ==)=====)( =(*====-=(-==(-)= |
t |
|
5(+= |
-=*(+ n |
|
|
|
ГЛАВА 1 5 |
класс: каждый сам за себя |
339 |