- •1. Лекция: Visual Studio .Net, Framework .Net
- •Visual Studio .Net - открытая среда разработки
- •Открытость
- •Framework .Net - единый каркас среды разработки
- •Библиотека классов FCL - статический компонент каркаса
- •Единство каркаса
- •Встроенные примитивные типы
- •Структурные типы
- •Архитектура приложений
- •Модульность
- •Общеязыковая исполнительная среда CLR - динамический компонент каркаса
- •Двухэтапная компиляция. Управляемый модуль и управляемый код
- •Виртуальная машина
- •Дизассемблер и ассемблер
- •Метаданные
- •Сборщик мусора - Garbage Collector - и управление памятью
- •Исключительные ситуации
- •События
- •Общие спецификации и совместимые модули
- •2. Лекция: Язык C# и первые проекты
- •Создание C#
- •Виды проектов
- •Консольный проект
- •Windows-проект
- •Начало начал - точка "большого взрыва"
- •Выполнение проекта по умолчанию после "большого взрыва"
- •Проект WindowsHello
- •3. Лекция: Система типов языка С#
- •Общий взгляд
- •Система типов
- •Типы или классы? И типы, и классы
- •Семантика присваивания
- •Преобразование к типу object
- •Примеры преобразований
- •Семантика присваивания. Преобразования между ссылочными и значимыми типами
- •Операции "упаковать" и "распаковать" (boxing и unboxing).
- •4. Лекция: Преобразования типов
- •Где, как и когда выполняются преобразования типов?
- •Преобразования ссылочных типов
- •Преобразования типов в выражениях
- •Преобразования внутри арифметического типа
- •Явные преобразования
- •Преобразования строкового типа
- •Преобразования и класс Convert
- •Проверяемые преобразования
- •Исключения и охраняемые блоки. Первое знакомство
- •Опасные вычисления в охраняемых проверяемых блоках
- •Опасные вычисления в охраняемых непроверяемых блоках
- •Опасные преобразования и методы класса Convert
- •5. Лекция: Переменные и выражения
- •Объявление переменных
- •Проект Variables
- •Синтаксис объявления
- •Время жизни и область видимости переменных
- •Поля
- •Локальные переменные
- •Глобальные переменные уровня процедуры. Существуют ли?
- •Константы
- •6. Лекция: Выражения. Операции в выражениях
- •Выражения
- •Приоритет и порядок выполнения операций
- •Перегрузка операций
- •С чего начинается выполнение выражения
- •Операции "увеличить" и "уменьшить" (increment, decrement)
- •Операции sizeof и typeof
- •Как получить подробную информацию о классе?
- •Статические поля и методы арифметических классов
- •Операция new
- •Арифметические операции
- •Операции отношения
- •Операции проверки типов
- •Операции сдвига
- •Логические операции
- •Условное выражение
- •Операция приведения к типу
- •7. Лекция: Присваивание и встроенные функции
- •Присваивание
- •Специальные случаи присваивания
- •Определенное присваивание
- •Еще раз о семантике присваивания
- •Рассмотрим объявления:
- •Класс Math и его функции
- •Класс Random и его функции
- •8. Лекция: Операторы языка C#
- •Операторы языка C#
- •Оператор присваивания
- •Блок или составной оператор
- •Пустой оператор
- •Операторы выбора
- •Оператор if
- •Оператор switch
- •Операторы перехода
- •Оператор goto
- •Операторы break и continue
- •Оператор return
- •Операторы цикла
- •Оператор for
- •Циклы While
- •Цикл foreach
- •9. Лекция: Процедуры и функции - методы класса
- •Процедуры и функции - функциональные модули
- •Процедуры и функции - методы класса
- •Процедуры и функции. Отличия
- •Описание методов (процедур и функций). Синтаксис
- •Список формальных аргументов
- •Тело метода
- •Вызов метода. Синтаксис
- •О соответствии списков формальных и фактических аргументов
- •Вызов метода. Семантика
- •Что нужно знать о методах?
- •Почему у методов мало аргументов?
- •Поля класса или функции без аргументов?
- •Пример: две версии класса Account
- •Функции с побочным эффектом
- •Методы. Перегрузка
- •10. Лекция: Корректность методов. Рекурсия
- •Корректность методов
- •Инварианты и варианты цикла
- •Рекурсия
- •Рекурсивное решение задачи "Ханойские башни"
- •Быстрая сортировка Хоара
- •11. Лекция: Массивы языка C#
- •Общий взгляд
- •Объявление массивов
- •Объявление одномерных массивов
- •Динамические массивы
- •Многомерные массивы
- •Массивы массивов
- •Процедуры и массивы
- •12. Лекция: Класс Array и новые возможности массивов
- •Класс Array
- •Массивы как коллекции
- •Сортировка и поиск. Статические методы класса Array
- •Класс Object и массивы
- •Массивы объектов
- •Массивы. Семантика присваивания
- •13. Лекция: Символы и строки постоянной длины в C#
- •Общий взгляд
- •Строки С++
- •Строки С#
- •Класс char
- •Класс char[] - массив символов
- •Существует ли в C# тип char*
- •14. Лекция: Строки C#. Классы String и StringBuilder
- •Класс String
- •Объявление строк. Конструкторы класса string
- •Операции над строками
- •Строковые константы
- •Неизменяемый класс string
- •Статические свойства и методы класса String
- •Метод Format
- •Методы Join и Split
- •Динамические методы класса String
- •Класс StringBuilder - построитель строк
- •Объявление строк. Конструкторы класса StringBuilder
- •Операции над строками
- •Основные методы
- •Емкость буфера
- •15. Лекция: Регулярные выражения
- •Пространство имен RegularExpression и классы регулярных выражений
- •Немного теории
- •Синтаксис регулярных выражений
- •Классы Group и GroupCollection
- •Классы Capture и CaptureCollection
- •Перечисление RegexOptions
- •Класс RegexCompilationInfo
- •Примеры работы с регулярными выражениями
- •Пример "чет и нечет"
- •Пример "око и рококо"
- •Пример "кок и кук"
- •Пример "обратные ссылки"
- •Пример "Дом Джека"
- •Пример "Атрибуты"
- •16. Лекция: Классы
- •Классы и ООП
- •Две роли классов
- •Синтаксис класса
- •Поля класса
- •Доступ к полям
- •Методы класса
- •Доступ к методам
- •Методы-свойства
- •Индексаторы
- •Операции
- •Статические поля и методы класса
- •Константы
- •Конструкторы класса
- •Деструкторы класса
- •Проектирование класса Rational
- •Свойства класса Rational
- •Конструкторы класса Rational
- •Методы класса Rational
- •Закрытый метод НОД
- •Печать рациональных чисел
- •Тестирование создания рациональных чисел
- •Операции над рациональными числами
- •Константы класса Rational
- •17. Лекция: Структуры и перечисления
- •Развернутые и ссылочные типы
- •Классы и структуры
- •Структуры
- •Синтаксис структур
- •Класс Rational или структура Rational
- •Встроенные структуры
- •Еще раз о двух семантиках присваивания
- •Перечисления
- •Персоны и профессии
- •18. Лекция: Отношения между классами. Клиенты и наследники
- •Отношения между классами
- •Отношения "является" и "имеет"
- •Отношение вложенности
- •Расширение определения клиента класса
- •Отношения между клиентами и поставщиками
- •Сам себе клиент
- •Наследование
- •Добавление полей потомком
- •Конструкторы родителей и потомков
- •Добавление методов и изменение методов родителя
- •Статический контроль типов и динамическое связывание
- •Три механизма, обеспечивающие полиморфизм
- •Пример работы с полиморфным семейством классов
- •Абстрактные классы
- •Классы без потомков
- •19. Лекция: Интерфейсы. Множественное наследование
- •Интерфейсы
- •Две стратегии реализации интерфейса
- •Преобразование к классу интерфейса
- •Проблемы множественного наследования
- •Коллизия имен
- •Наследование от общего предка
- •Встроенные интерфейсы
- •Упорядоченность объектов и интерфейс IComparable
- •Клонирование и интерфейс ICloneable
- •Сериализация объектов
- •Класс с атрибутом сериализации
- •Интерфейс ISerializable
- •20. Лекция: Функциональный тип в C#. Делегаты
- •Как определяется функциональный тип и как появляются его экземпляры
- •Функции высших порядков
- •Вычисление интеграла
- •Построение программных систем методом "раскрутки". Функции обратного вызова
- •Наследование и полиморфизм - альтернатива обратному вызову
- •Делегаты как свойства
- •Операции над делегатами. Класс Delegate
- •Операции "+" и "-"
- •Пример "Комбинирование делегатов"
- •Пример "Плохая служба"
- •21. Лекция: События
- •Классы с событиями
- •Класс sender. Как объявляются события?
- •Делегаты и события
- •Как зажигаются события
- •Классы receiver. Как обрабатываются события
- •Классы с событиями, допустимые в каркасе .Net Framework
- •Пример "Списки с событиями"
- •Класс sender
- •Классы receiver
- •Две проблемы с обработчиками событий
- •Игнорирование коллег
- •Переопределение значений аргументов события
- •Классы с большим числом событий
- •Проект "Город и его службы"
- •22. Лекция: Универсальность. Классы с родовыми параметрами
- •Наследование и универсальность
- •Синтаксис универсального класса
- •Класс с универсальными методами
- •Два основных механизма объектной технологии
- •Стек. От абстрактного, универсального класса к конкретным версиям
- •Ограниченная универсальность
- •Синтаксис ограничений
- •Список с возможностью поиска элементов по ключу
- •Как справиться с арифметикой
- •Родовое порождение класса. Предложение using
- •Универсальность и специальные случаи классов
- •Универсальные структуры
- •Универсальные интерфейсы
- •Универсальные делегаты
- •Framework .Net и универсальность
- •23. Лекция: Отладка и обработка исключительных ситуаций
- •Корректность и устойчивость программных систем
- •Жизненный цикл программной системы
- •Три закона программотехники
- •Первый закон (закон для разработчика)
- •Второй закон (закон для пользователя)
- •Третий закон (закон чечако)
- •Отладка
- •Создание надежного кода
- •Искусство отладки
- •Отладочная печать и условная компиляция
- •Классы Debug и Trace
- •Метод Флойда и утверждения Assert
- •Классы StackTrace и BooleanSwitch
- •Отладка и инструментальная среда Visual Studio .Net
- •Обработка исключительных ситуаций
- •Обработка исключений в языках C/C++
- •Схема обработки исключений в C#
- •Выбрасывание исключений. Создание объектов Exception
- •Захват исключения
- •Параллельная работа обработчиков исключений
- •Блок finally
- •Схема Бертрана обработки исключительных ситуаций
- •Класс Exception
- •Организация интерфейса
- •Форма и элементы управления
- •Взаимодействие форм
- •Модальные и немодальные формы
- •Передача информации между формами
- •Образцы форм
- •Главная кнопочная форма
- •Шаблон формы для работы с классом
- •Работа со списками (еще один шаблон)
- •Элемент управления класса ListBox
- •Наследование форм
- •Два наследника формы TwoLists
- •Огранизация меню в формах
- •Создание меню в режиме проектирования
- •Классы меню
- •Создание инструментальной панели с командными кнопками
- •Рисование в форме
- •Класс Graphics
- •Методы класса Graphics
- •Класс Pen
- •Класс Brush
- •Проект "Паутина Безье, кисти и краски"
- •Паутина Безье
- •Событие Paint
- •Кисти и краски
- •Абстрактный класс Figure
- •Классы семейства геометрических фигур
- •Класс Ellipse
- •Класс Circle
- •Класс LittleCircle
- •Класс Rect
- •Класс Square
- •Класс Person
- •Список с курсором. Динамические структуры данных
- •Классы элементов списка
- •Организация интерфейса
double[] ard = new double[3]; for (int i= 0;i<3;i++)
{
//массивы могут быть без инициализации ard[i] += i+1;
ars[i] += i.ToString()+1; Console.WriteLine("ard[" +i + "]=" +ard[i] +
"; ars[" +i + "]=" +ars[i]);
}
Заметьте, в этом фрагменте переменная an обязана быть инициализированной, а массивы ard и ars не инициализируются и спокойно участвуют в вычислениях.
Еще раз о семантике присваивания
Подводя итоги рассмотрения присваивания x=e, следует отметить, что семантика присваивания далеко не столь проста, как может показаться с первого взгляда. Напомню, что деление типов на значимые и ссылочные приводит к двум семантикам присваивания. Будет ли семантика значимой или ссылочной - определяется типом левой части присваивания. Переменные значимых типов являются единоличными владельцами памяти, в которой хранятся их значения. При значимом присваивании память для хранения значений остается той же - меняются лишь сами значения, хранимые в ней. Переменные ссылочных типов (объекты) являются ссылками на реальные объекты динамической памяти. Ссылки могут разделять одну и ту же область памяти - ссылаться на один и тот же объект. Ссылочное присваивание - это операция над ссылками. В результате ссылочного присваивания ссылка начинает указывать на другой объект.
Рассмотрим объявления:
int x=3, y=5; object obj1, obj2;
Здесь объявлены четыре сущности: две переменные значимого типа и две - объектного. Значимые переменные x и y проинициализированы и имеют значения, объектные переменные obj1 и obj2 являются пустыми ссылками со значением void. Рассмотрим
присваивания:
obj1 = x; obj2 = y;
Эти присваивания ссылочные (из-за типа левой части), поэтому правая часть приводится к ссылочному типу. В результате неявного преобразования - операции boxing - в динамической памяти создаются два объекта, обертывающие соответственно значения переменных x и y. Сущности obj1 и obj2 получают значения ссылок на эти объекты.
Класс Math и его функции
Кроме переменных и констант, первичным материалом для построения выражений являются функции. Большинство их в проекте будут созданы самим программистом, но не обойтись и без встроенных функций. Умение работать в среде Visual Studio .Net предполагает знание встроенных возможностей этой среды, знание возможностей каркаса Framework .Net, пространств имен, доступных при программировании на языке C#, а также соответствующих встроенных классов и функций этих классов. Продолжим знакомство с возможностями, предоставляемыми пространством имен System. Мы уже познакомились с классом Convert этого пространства и частично с классом Console. Давайте рассмотрим еще один класс - класс Math, содержащий стандартные
математические функции, без которых трудно обойтись при построении многих выражений. Этот класс содержит два статических поля, задающих константы E и PI, а также 23 статических метода. Методы задают:
•тригонометрические функции - Sin, Cos, Tan;
•обратные тригонометрические функции - ASin, ACos, ATan, ATan2 (sinx, cosx);
•гиперболические функции - Tanh, Sinh, Cosh;
•экспоненту и логарифмические функции - Exp, Log, Log10;
•модуль, корень, знак - Abs, Sqrt, Sign;
•функции округления - Ceiling, Floor, Round;
•минимум, максимум, степень, остаток - Min, Max, Pow, IEEEReminder.
Вособых пояснениях эти функции не нуждаются. Приведу пример:
///<summary>
///работа с функциями класса Math
///</summary>
public void MathFunctions()
{
double a, b,t,t0,dt,y; string NameFunction;
Console.WriteLine("Введите имя F(t)исследуемой функции a*F(b*t)" + " (sin, cos, tan, cotan)");
NameFunction = Console.ReadLine(); Console.WriteLine("Введите параметр a (double)"); a= double.Parse(Console.ReadLine()); Console.WriteLine("Введите параметр b (double)"); b= double.Parse(Console.ReadLine());
Console.WriteLine("Введите начальное время t0(double)"); t0= double.Parse(Console.ReadLine());
const int points = 10; dt = 0.2;
for(int i = 1; i<=points; i++)
{
t = t0 + (i-1)* dt; switch (NameFunction)
{
case ("sin"):
y = a*Math.Sin(b*t); break;
case ("cos"):
y = a*Math.Cos(b*t); break;
case ("tan"):
y = a*Math.Tan(b*t); break;
case ("cotan"):
y = a/Math.Tan(b*t); break;
case ("ln"):
y = a*Math.Log(b*t); break;
case ("tanh"):
y = a*Math.Tanh(b*t); break;
default:
y=1;
break;
}//switch
Console.WriteLine ("t = " + t + "; " + a +"*" + NameFunction +"(" + b + "*t)= " + y + ";");
}//for
double u = 2.5, v = 1.5, p,w; p= Math.Pow(u,v);
w = Math.IEEERemainder(u,v); Console.WriteLine ("u = " + u + "; v= " + v +
"; power(u,v)= " + p + "; reminder(u,v)= " + w); }//MathFunctions
Заметьте, в примерах программного кода я постепенно расширяю диапазон используемых средств. Часть из этих средств уже описана, а часть (например, оператор цикла for и оператор выбора switch) будут описаны позже. Те, у кого чтение примеров вызывает затруднение, смогут вернуться к ним при повторном чтении книги.
Коротко прокомментирую этот код. В данном примере пользователь определяет, какую функцию он хочет вычислить и при каких значениях ее параметров. Некоторые параметры задаются константами и инициализированными переменными, но для большинства их значения вводятся пользователем. Одна из целей этого фрагмента состоит в демонстрации консольного ввода данных разного типа, при котором используется описанный ранее метод Parse.
Функция, заданная пользователем, вычисляется в операторе switch. Здесь реализован выбор из 6 стандартных функций, входящих в джентльменский набор класса Math.
Вызов еще двух функций из класса Math содержится в двух последних строчках этой процедуры. На рис. 7.1 можно видеть результаты ее работы.
Рис. 7.1. Результаты работы процедуры MathFunctions
Класс Random и его функции
Умение генерировать случайные числа требуется во многих приложениях. Класс Random содержит все необходимые для этого средства. Класс Random имеет конструктор класса: для того, чтобы вызывать методы класса, нужно вначале создавать экземпляр класса. Этим Random отличается от класса Math, у которого все поля и методы - статические, что позволяет обойтись без создания экземпляров класса Math.
Как и всякий "настоящий" класс, класс Random является наследником класса Object, а, следовательно, имеет в своем составе и методы родителя. Рассмотрим только оригинальные методы класса Random со статусом public, необходимые для генерирования последовательностей случайных чисел. Класс имеет защищенные методы, знание которых полезно при необходимости создания собственных потомков класса Random, но этим мы заниматься не будем.
Начнем рассмотрение с конструктора класса. Он перегружен и имеет две реализации. Одна из них позволяет генерировать неповторяющиеся при каждом запуске серии случайных чисел. Начальный элемент такой серии строится на основе текущей даты и времени, что гарантирует уникальность серии. Этот конструктор вызывается без параметров. Он описан как public Random(). Другой конструктор с параметром - public Random (int) обеспечивает важную возможность генерирования повторяющейся серии случайных чисел. Параметр конструктора используется для построения начального элемента серии, поэтому при задании одного и того же значения параметра серия будет повторяться.
Перегруженный метод public int Next() при каждом вызове возвращает положительное целое, равномерно распределенное в некотором диапазоне. Диапазон задается параметрами метода. Три реализации метода отличаются набором параметров:
•public int Next () - метод без параметров выдает целые положительные числа во всем положительном диапазоне типа int;
•public int Next (int max) - выдает целые положительные числа в диапазоне
[0,max];
•public int Next (int min, int max) - выдает целые положительные числа в диапазоне [min,max].
Метод public double NextDouble () имеет одну реализацию. При каждом вызове этого метода выдается новое случайное число, равномерно распределенное в интервале [0- 1).
Еще один полезный метод класса Random позволяет при одном обращении получать целую серию случайных чисел. Метод имеет параметр - массив, который и будет заполнен случайными числами. Метод описан как public void NextBytes (byte[] buffer). Так как параметр buffer представляет массив байтов, то, естественно, генерированные случайные числа находятся в диапазоне [0, 255].
Приведу теперь пример работы со случайными числами. Как обычно, для проведения экспериментов по генерации случайных чисел я создал метод Rand в классе Testing. Вот программный код этого метода:
///<summary>
///Эксперименты с классом Random
///</summary>
public void Rand()
{
const int initRnd = 77; Random realRnd = new Random();
Random repeatRnd = new Random(initRnd); // случайные числа в диапазоне [0,1)
Console.WriteLine("случайные числа в диапазоне[0,1)"); for(int i =1; i <= 5; i++)
{
Console.WriteLine("Число " + i + "= " + realRnd.NextDouble() );
}
// случайные числа в диапазоне[min,max] int min = -100, max=-10;
Console.WriteLine("случайные числа в диапазоне [" + min +"," + max + "]");
for(int i =1; i <= 5; i++)
{
Console.WriteLine("Число " + i + "= " + realRnd.Next(min,max) );
}
// случайный массив байтов byte[] bar = new byte[10]; repeatRnd.NextBytes(bar);
Console.WriteLine("Массив случайных чисел в диапазоне
[0, 255]");
for(int i =0; i < 10; i++)
{
Console.WriteLine("Число " + i + "= " +bar[i]);
}
}//Rand
Приведу краткий комментарий к тексту программы. Вначале создаются два объекта класса Random. У этих объектов разные конструкторы. Объект с именем realRnd позволяет генерировать неповторяющиеся серии случайных чисел. Объект repeatRnd дает возможность повторить при необходимости серию. Метод NextDouble создает серию случайных чисел в диапазоне [0, 1). Вызываемый в цикле метод Next с двумя параметрами создает серию случайных отрицательных целых, равномерно распределенных в диапазоне [-100, -10]. Метод NextBytes объекта repeatRnd позволяет получить при одном вызове массив случайных чисел из диапазона [0, 255]. Результаты вывода можно увидеть на рис. 7.2.
Рис. 7.2. Генерирование последовательностей случайных чисел в процедуре Rand
На этом заканчивается рассмотрение темы выражений языка C#.