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

Вот в чем состоит работа и нициал изаторов . Как _accountNumber, так и |
||
_balance получают значения как часть объявления, эффект которого аналоги |
||
чен использованию указанного кода в конструкторе. |
||
Надо очень четко представлять себе картину происходящего. Вы можете ре |
||
шить, |
что это выражение присваивает значение О . О переменной _balance не |
|
посредственно. Но ведь _balance существует только как часть некоторого объ |
||
екта. Таким образом, присваивание не выпол няется до тех пор, пока не будет |
||
создан объект _BankAccount. Рассматриваемое присваивание осуществляется |
||
всякий раз при создании объекта. |
||
Заметим, что статический член-данные _nextAccountNumЬer инициал изи |
||
руется при первом обращении к классу Ban kAccount (как вы убедились при |
||
вы полнении демонстрационной программ ы в отладчике), т.е. при обращении к |
||
любому свойству или методу объекта, владеющему статическим членом, в том |
||
числе к конструктору. |
||
|
Будуч и инициализированным, статический член повторно не ини |
|
|
циализируется, сколько бы объектов вы н и создавали. Этим он от |
|
рс,мdaнa |
л ичается от нестатических членов. И нициализаторы выполняются |
|
в порядке их появления в объя влении класса. Если С# встречает и |
||
|
||
|
инициализаторы, и конструктор, то инициализаторы выполняются |
|
|
раньше тела конструктора. |
Конструирование с инициализаторами
Давайте в программе Demons trateCustomConst ructor перенесем вызов new MyOtherObj ect ( ) из конструктора MyObj ect в объявление так, как показа но в приведенном далее фрагменте исходного текста полужирным шрифтом, и
изменим второй вызов WriteLine ( ) . |
|
|
, , |
|
м ы П |
|
|
|
, , |
о |
я xП |
|
||
|
б ы |
|
|
б ы |
ы ы П |
v |
б ым |
ы ь |
,, |
ы |
ы ы в |
|
|
|
|
б ы |
ыПы |
f |
ЧАСТЬ 2 |
BЬ)((.1B)Ь1.(Г0))(B |
.( |
.0ВВ1. |
(Г0)1B )0 |

Сравните вывод на экран такой модифицированной программы с выводом на экран исходной программы меоиэтссосеeЭтсиоeиэт с) пуви)пn
|
|
"ш :имл s |
" |
,'l ,( |
"ш: и м лтоs |
|
|
|
|||
u сздt с я |
сбм, |
лж 5чоаетч |
а1екож |
|
|
u сзд tся |
сбм, |
лж .Рч оаетч аLекож |
|
||
n |
|
" ,'l |
,( |
|
, |
|
" |
,'l |
,( |
||
|
(,им |
к . . |
|||
|
,щ[ |
|
|
Инициализация объекта без конструктора
Предположим, у вас есть небольшой класс для представления студента:
т Р:( (rш |
6 |
,,им |
|
|
|
|
т |
s:( |
щ:им1 |
)шг, |
1, |
W , V |
, V |
т |
r:( |
щ:им1 |
w, ,щ, |
1, |
V |
|
т |
:( ,р |
, |
Cщш,,,р: |
им |
wщш, 1, |
1, V , Г |
Объект зспнеэсnимеет три открытых свойства, lооеЕnбнн) еттnи ,)оне "иПэсn бВесояерnкоторые содержат всю основную информацию о студенте. Обычно при создании нового объекта зспнеэсnвы должны инициализировать его свой ства lоое,nбннсеттnи ,сонеhихэсбВесояеnпримерно таким образом:
6,,имщшим,шР=
= = |
= |
= |
= |
|
= |
Если класс з с пнеэсnимеет конструктор, можно поступить следующим образом:
6 |
,,имщшим,шre |
им, 6 |
,,имnо1шим,шr 6т3 шщо ( |
|
у : и D ,r г |
6 щ,, |
" Bщ рщ3 прим ,у ,им(,") й pppppо " D к Я: s V |
Однако, увы, у класса зспнеэсnнет другого конструктора, кроме конструк тора по умолчанию, автоматически создаваемого С#, и не принимающего ни каких аргументов.
В С# 3 .0 и более поздних версиях можно упростить такую инициа лизацию при помощи кода, выглядящего подозрительно похожим на конструктор:
кушмлпсиВ |
6 ,,им щшим,шw. |
им, 6 |
,,им |
|
|||
|
)шг, = = |
= |
= |
|
= |
= |
|
|
= |
|
|
ГЛАВА 1 5 класс: каждый сам за себя 345

Чем отличаются эти два примера? Первый, использующий конструктор, со держит C xs C,,C в" которые заключены две строки и одно ч исло с плава ющей точкой, разделенные запятыми. Во втором примере с применением ново
го синтаксиса инициализации вместо этого используются |
"ч,xs p ,C lв |
|
которых содержатся три lч |
fNЕ N, "разделенные запятыми. Этот синтаксис |
|
работает следующим образом: |
|
.
Данный синтаксис инициализации объектов позволяет выполнять присва ивание любому разрешающему присваивание свойству 0'"5vдобъекта в блоке кода (в фигурных скобках). Этот блок предназначен для инициализации объ екта. Заметим, что таким образом можно назначать значения только открытым свойствам, но не закрытым, а кроме того, в этом коде нельзя вызывать никакие методы объекта или выполнять какую-то и ную работу.
Такой синтаксис весьма краток - одна инструкция вместо трех. Он упро щает создание инициализированных объектов, которые вы не можете иници ализировать при помощи конструктора. Дает ли новый синтаксис инициали зации что-либо, кроме удобства? Не м ногое, но удобство всегда находится в верху списка предпочтений практикующего программиста (так же, как и кра ткость). Кроме того, эта возможность очень важна при работе с анонимными классами.
Пользуйтесь этой возможностью свободно, так, как вам подсказыва ет ваша интуиция. Если вы хотите узнать о ней побольше, поищите в
справочной системе o ject initializer.
СОВЕТ
При1V1ене ие__чnен()В с кодом
Члены с кодом (expression-bodied members) впервые появились в С# 6.0 как средство, облегчающее определение методов и свойств. В С# 7.0 члены с ко дом работают также с конструкторами, деструкторами, методами доступа к свойствам и событиям.
бе чи йт юлщц лaе и е жщгщхе и ецщ
Вприведенном примере показано, как можно было создавать методы до С# 6.0:
|
|
s |
|
м |
ч |
|
, |
S |
, |
|
|
|||
np c |
,л<s. |
и дьi |
п")еоrо |
ивпе виознееоп оио rин тт ви озневп ен ,a |

При работе с членами с кодом можно уменьшить количество строк кода до одной:
ЗАПОМНИ! puЫic int RectArea (Rectangle rect ) => rect . Height * rect . Width;
Хотя обе версии выполняют одно и то же действие, вторая версия намного короче и ее легче написать. Компромисс заключается в том, что вторая версия может быть сложнее для понимания.
Определение свойств с кодом
Свойства с кодом работают подобно методам: вы объявляете свойство с по мощью единственной строки кода:
puЫic int RectArea => _rect . Height * _rect . Width;
В этом примере предполагается, что у нас определен закрытый член _rect и что вы хотите получить значение, равное площади прямоугольника.
Определение конструкторов и деструкторов с кодом
ВС# 7.0 можно использовать тот же подход для работы с конструктором.
Вболее ранних версиях С# можно создавать конструктор следующим образом:
puЬlic EmpData ( )
{
Здесь конструктор класса EmpData устанавливает значение закрытой пере менной _name равным "Harvey". С# 7.0 для этого достаточно одной строки: puЫic EmpData ( ) => _name = "Harvey" ;
Деструкторы работают в основном так же, как и конструкторы. Вместо мно гих строк вы можете использовать только одну.
Определение методов доступа к свойствам с кодом Методы доступа к свойствам также могут извлечь выгоду из членов с кодом.
Вот типичный метод доступа в С# 6.0 с get и set:
private int myVar; puЫic MyVar- {
get
{
set
йж
ГЛАВА 1 5 класс: каждый сам за себя 347