- •Visual Studio .Net - открытая среда разработки
- •Открытость
- •Framework .Net - единый каркас среды разработки
- •Библиотека классов fcl - статический компонент каркаса
- •Единство каркаса
- •Встроенные примитивные типы
- •Структурные типы
- •Архитектура приложений
- •Модульность
- •Общеязыковая исполнительная среда clr - динамический компонент каркаса
- •Двухэтапная компиляция. Управляемый модуль и управляемый код
- •Виртуальная машина
- •Дизассемблер и ассемблер
- •Метаданные
- •Сборщик мусора - Garbage Collector - и управление памятью
- •Исключительные ситуации
- •События
- •Общие спецификации и совместимые модули
- •Создание c#
- •Виды проектов
- •Консольный проект
- •Windows-проект
- •Начало начал - точка "большого взрыва"
- •Выполнение проекта по умолчанию после "большого взрыва"
- •Проект WindowsHello
- •На этом мы закончим первое знакомство с проектaми на c# и в последующих лекциях приступим к сОбщий взгляд
- •Система типов
- •Типы или классы? и типы, и классы
- •Семантика присваивания
- •Преобразование к типу object
- •Примеры преобразований
- •Семантика присваивания. Преобразования между ссылочными и значимыми типами
- •Операции "упаковать" и "распаковать" (boxing и unboxing).
- •Где, как и когда выполняются преобразования типов?
- •Преобразования ссылочных типов
- •Преобразования типов в выражениях
- •Преобразования внутри арифметического типа
- •Явные преобразования
- •Преобразования строкового типа
- •Преобразования и класс Convert
- •Проверяемые преобразования
- •Исключения и охраняемые блоки. Первое знакомство
- •Опасные вычисления в охраняемых проверяемых блоках
- •Опасные вычисления в охраняемых непроверяемых блоках
- •Опасные преобразования и методы класса Convert
- •Объявление переменных
- •Проект Variables
- •Синтаксис объявления
- •Время жизни и область видимости переменных
- •Глобальные переменные уровня модуля. Существуют ли они в c#?
- •Локальные переменные
- •Глобальные переменные уровня процедуры. Существуют ли?
- •Константы
- •Выражения
- •Приоритет и порядок выполнения операций
- •Перегрузка операций
- •С чего начинается выполнение выражения
- •Операции "увеличить" и "уменьшить" (increment, decrement)
- •Операции sizeof и typeof
- •Как получить подробную информацию о классе?
- •Статические поля и методы арифметических классов
- •Операция new
- •Арифметические операции
- •Операции отношения
- •Операции проверки типов
- •Операции сдвига
- •Логические операции
- •Условное выражение
- •Операция приведения к типу
- •В данном примере явное преобразование из типа double в тип int выполняется, а преобразованиПрисваивание
- •Специальные случаи присваивания
- •Определенное присваивание
- •Еще раз о семантике присваивания
- •Рассмотрим объявления:
- •Класс Math и его функции
- •Класс Random и его функции
- •Операторы языка c#
- •Оператор присваивания
- •Блок или составной оператор
- •Пустой оператор
- •Операторы выбора
- •Оператор if
- •Оператор switch
- •Операторы перехода
- •Оператор goto
- •Операторы break и continue
- •Оператор return
- •Операторы цикла
- •Оператор for
- •Циклы While
- •Цикл foreach
- •Процедуры и функции - функциональные модули
- •Процедуры и функции - методы класса
- •Процедуры и функции. Отличия
- •Описание методов (процедур и функций). Синтаксис
- •Список формальных аргументов
- •Тело метода
- •Вызов метода. Синтаксис
- •О соответствии списков формальных и фактических аргументов
- •Вызов метода. Семантика
- •Что нужно знать о методах?
- •Почему у методов мало аргументов?
- •Поля класса или функции без аргументов?
- •Пример: две версии класса Account
- •Функции с побочным эффектом
- •Методы. Перегрузка
- •Корректность методов
- •Инварианты и варианты цикла
- •Рекурсия
- •Рекурсивное решение задачи "Ханойские башни"
- •Быстрая сортировка Хоара
- •Общий взгляд
- •Объявление массивов
- •Объявление одномерных массивов
- •Динамические массивы
- •Многомерные массивы
- •Массивы массивов
- •Процедуры и массивы
- •Класс Array
- •Массивы как коллекции
- •Сортировка и поиск. Статические методы класса Array
- •Сводка свойств и методов класса Array
- •Класс Object и массивы
- •Массивы объектов
- •Массивы. Семантика присваивания
- •Общий взгляд
- •Строки с#
- •Класс char
- •Класс char[] - массив символов
- •Существует ли в c# тип char*
- •Пространство имен RegularExpression и классы регулярных выражений
- •Немного теории
- •Синтаксис регулярных выражений
- •Знакомство с классами пространства RegularExpressions
- •Класс Regex
- •Классы Match и MatchCollection
- •Классы Group и GroupCollection
- •Классы Capture и CaptureCollection
- •Перечисление RegexOptions
- •Класс RegexCompilationInfo
- •Примеры работы с регулярными выражениями
- •Пример "чет и нечет"
- •Пример "око и рококо"
- •Пример "кок и кук"
- •Пример "обратные ссылки"
- •Пример "Дом Джека"
- •Пример "Атрибуты"
- •Классы и ооп
- •Две роли классов
- •Синтаксис класса
- •Поля класса
- •Доступ к полям
- •Методы класса
- •Доступ к методам
- •Методы-свойства
- •Индексаторы
- •Операции
- •Статические поля и методы класса
- •Константы
- •Конструкторы класса
- •Деструкторы класса
- •Проектирование класса Rational
- •Свойства класса Rational
- •Конструкторы класса Rational
- •Методы класса Rational
- •Закрытый метод нод
- •Печать рациональных чисел
- •Тестирование создания рациональных чисел
- •Операции над рациональными числами
- •Константы класса Rational
- •Развернутые и ссылочные типы
- •Классы и структуры
- •Структуры
- •Синтаксис структур
- •Класс Rational или структура Rational
- •Встроенные структуры
- •Еще раз о двух семантиках присваивания
- •Перечисления
- •Персоны и профессии
- •Отношения между классами
- •Отношения "является" и "имеет"
- •Отношение вложенности
- •Расширение определения клиента класса
- •Отношения между клиентами и поставщиками
- •Сам себе клиент
- •Наследование
- •Добавление полей потомком
- •Конструкторы родителей и потомков
- •Добавление методов и изменение методов родителя
- •Статический контроль типов и динамическое связывание
- •Три механизма, обеспечивающие полиморфизм
- •Пример работы с полиморфным семейством классов
- •Абстрактные классы
- •Классы без потомков
- •Интерфейсы
- •Две стратегии реализации интерфейса
- •Преобразование к классу интерфейса
- •Проблемы множественного наследования
- •Коллизия имен
- •Наследование от общего предка
- •Встроенные интерфейсы
- •Упорядоченность объектов и интерфейс iComparable
- •Клонирование и интерфейс iCloneable
- •Сериализация объектов
- •Класс с атрибутом сериализации
- •Интерфейс iSerializable
- •Как определяется функциональный тип и как появляются его экземпляры
- •Функции высших порядков
- •Вычисление интеграла
- •Построение программных систем методом "раскрутки". Функции обратного вызова
- •Наследование и полиморфизм - альтернатива обратному вызову
- •Делегаты как свойства
- •Операции над делегатами. Класс Delegate
- •Пример "Комбинирование делегатов"
- •Пример "Плохая служба"
- •Классы с событиями
- •Класс sender. Как объявляются события?
- •Делегаты и события
- •Как зажигаются события
- •Классы receiver. Как обрабатываются события
- •Классы с событиями, допустимые в каркасе .Net Framework
- •Пример "Списки с событиями"
- •Класс sender
- •Классы receiver
- •Две проблемы с обработчиками событий
- •Игнорирование коллег
- •Переопределение значений аргументов события
- •Классы с большим числом событий
- •Проект "Город и его службы"
- •Наследование и универсальность
- •Синтаксис универсального класса
- •Класс с универсальными методами
- •Два основных механизма объектной технологии
- •Стек. От абстрактного, универсального класса к конкретным версиям
- •Ограниченная универсальность
- •Синтаксис ограничений
- •Список с возможностью поиска элементов по ключу
- •Как справиться с арифметикой
- •Родовое порождение класса. Предложение using
- •Универсальность и специальные случаи классов
- •Универсальные структуры
- •Универсальные интерфейсы
- •Универсальные делегаты
- •Framework .Net и универсальность
- •Корректность и устойчивость программных систем
- •Жизненный цикл программной системы
- •Три закона программотехники Первый закон (закон для разработчика)
- •Второй закон (закон для пользователя)
- •Третий закон (закон чечако)
- •Отладка
- •Создание надежного кода
- •Искусство отладки
- •Отладочная печать и условная компиляция
- •Классы Debug и Trace
- •Метод Флойда и утверждения Assert
- •Классы StackTrace и BooleanSwitch
- •Отладка и инструментальная среда Visual Studio .Net
- •Обработка исключительных ситуаций
- •Выбрасывание исключений. Создание объектов Exception
- •Захват исключения
- •Параллельная работа обработчиков исключений
- •Блок finally
- •Класс Exception
- •Организация интерфейса
- •Форма и элементы управления
- •Взаимодействие форм
- •Модальные и немодальные формы
- •Передача информации между формами
- •Образцы форм
- •Главная кнопочная форма
- •Шаблон формы для работы с классом
- •Работа со списками (еще один шаблон)
- •Элемент управления класса ListBox
- •Наследование форм
- •Два наследника формы TwoLists
- •Огранизация меню в формах
- •Создание меню в режиме проектирования
- •Классы меню
- •Создание инструментальной панели с командными кнопками
- •Рисование в форме
- •Класс Graphics
- •Методы класса Graphics
- •Класс Pen
- •Класс Brush
- •Проект "Паутина Безье, кисти и краски"
- •Паутина Безье
- •Событие Paint
- •Кисти и краски
- •Абстрактный класс Figure
- •Классы семейства геометрических фигур
- •Класс Ellipse
- •Класс Circle
- •Класс LittleCircle
- •Класс Rect
- •Класс Square
- •Класс Person
- •Список с курсором. Динамические структуры данных
- •Классы элементов списка
- •Организация интерфейса
Пример "Плохая служба"
Как быть, если в списке вызовов есть "плохой" экземпляр, при вызове которого возникает ошибка, приводящая к выбрасыванию исключительной ситуации? Тогда стоящие за ним в очереди экземпляры не будут вызваны, хотя они вполне могли бы выполнить свою часть работы. В этом случае полезно использовать метод GetInvocationList и в цикле поочередно вызывать делегатов. Вызов делегата следует поместить в охраняемый блок, тогда при возникновении исключительной ситуации в обработчике ситуации можно получить и выдать пользователю всю информацию о нарушителе, а цикл продолжит выполнение очередных делегатов из списка вызова.
Добавим в класс Combination "плохого" кандидата, который пытается делить на ноль:
//метод, вызывающий исключительную ситуацию
public static void BadService(string mes)
{
int i =7, j=5, k=0;
Console.WriteLine("Bad Service: Zero Divide");
j=i/k;
}
Создадим процедуру, в которой в списке вызовов есть хорошие и плохие кандидаты. Эта процедура использует управление исключительными ситуациями, о которых подробнее будет рассказано в последующих лекциях.
public void TestBadJob()
{
MesToPers Comb;
Comb = (MesToPers)Delegate.Combine(Combination.Ambulanceman,
Combination.Policeman);
Comb = (MesToPers)Delegate.Combine(Comb,
new MesToPers(Combination.BadService));
Comb = (MesToPers)Delegate.Combine(Comb,Combination.Fireman);
foreach(MesToPers currentJob in Comb.GetInvocationList())
{
try
{
currentJob("Пожар!");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(currentJob.Method.Name);
}
}
}//BadJob
Поясню, как будет работать эта процедура при ее вызове. Вначале две службы нормально отработают, но при вызове третьей службы возникнет исключительная ситуация "деление на ноль". Универсальный обработчик Exception перехватит эту ситуацию и напечатает как свойство Message объекта e, так и имя метода, вызвавшего исключительную ситуацию, используя свойство Method объекта, вызвавшего ситуацию. После завершения работы блока обработчика ситуации выполнение программы продолжится, выполнится следующий шаг цикла, и служба пожарных благополучно выполнит свою работу. Вот результаты вывода:
Рис. 20.7. "Плохая служба"
Разговор о делегатах еще не закончен. Он будет продолжен в следующей лекции, в которой рассмотрим классы с событиями. События основываются на делегатах.
Классы с событиями
Каждый объект является экземпляром некоторого класса. Класс задает свойства и поведение своих экземпляров. Методы класса определяют поведение объектов, свойства - их состояние. Все объекты обладают одними и теми же методами и, следовательно, ведут себя одинаково. Можно полагать, что методы задают врожденное поведение объектов. Этого нельзя сказать о свойствах - значения свойств объектов различны, так что экземпляры одного класса находятся в разных состояниях. Объекты класса "человек" могут иметь разные свойства: один - высокий, другой - низкий, один - сильный, другой - умный. Но методы у них одни: есть и спать, ходить и бегать. Как сделать поведение объектов специфическим? Как добавить им поведение, характерное для данного объекта? Один из наиболее известных путей - это наследование. Можно создать класс-наследник, у которого, наряду с унаследованным родительским поведением, будут и собственные методы. Например, наследником класса "человек" может быть класс "человек_образованный", обладающий методами: читать и писать, считать и программировать.
Есть еще один механизм, позволяющий объектам вести себя по-разному в одних и тех же обстоятельствах. Это механизм событий, рассмотрением которого мы сейчас и займемся. Класс, помимо свойств и методов, может иметь события. Содержательно, событием является некоторое специальное состояние, в котором может оказаться объект класса. Так, для объектов класса "человек" событием может быть рождение или смерть, свадьба или развод. О событиях в мире программных объектов чаще всего говорят в связи с интерфейсными объектами, у которых события возникают по причине действий пользователя. Так, командная кнопка может быть нажата - событие Click, документ может быть закрыт - событие Close, в список может быть добавлен новый элемент - событие Changed.
Интерфейсные и многие другие программные объекты обладают стандартным набором предопределенных событий. В конце этой лекции мы поговорим немного об особенностях работы с событиями таких объектов. Сейчас же наше внимание будет сосредоточено на классах, создаваемых программистом. Давайте разберемся, как для таких классов создаются и обрабатываются события. Класс, решивший иметь события, должен уметь, по крайней мере, три вещи:
-
объявить событие в классе;
-
зажечь в нужный момент событие, передав обработчику необходимые для обработки аргументы. (Под зажиганием или включением события понимается некоторый механизм, позволяющий объекту уведомить клиентов класса, что у него произошло событие.);
-
проанализировать, при необходимости, результаты события, используя значения выходных аргументов события, возвращенные обработчиком.
Заметьте, что, зажигая событие, класс посылает сообщение получателям события - объектам некоторых других классов. Будем называть класс, зажигающий событие, классом - отправителем сообщения (sender). Класс, чьи объекты получают сообщения, будем называть классом - получателем сообщения (receiver). Класс-отправитель сообщения, в принципе, не знает своих получателей. Он отправляет сообщение в межмодульное пространство. Одно и то же сообщение может быть получено и по-разному обработано произвольным числом объектов разных классов. Взгляните на схему, демонстрирующую взаимодействие объектов при посылке и получении сообщения.
Рис. 21.1. Взаимодействие объектов. Посылка и получение сообщения о событии