
- •Лабораторная работа 1 Тема: Типы данных и операторы языка с#. Массивы. Строки. Регулярные выражения
- •Типы данных c#
- •Преобразования типов
- •Преобразования строк в число. Класс Convert
- •Массивы в c#
- •Int[] k; //k – одномерный массив
- •Базовый класс System.Array
- •Строки в с# Класс Сhar
- •Класс String
- •Строковые константы
- •Пространство имен RegularExpression и классы регулярных выражений
- •Синтаксис регулярных выражений
- •Классы пространства RegularExpressions
- •1. Проработать примеры 1-8, данные в теоретических сведениях. Создать на их основе программы. Получить результаты работы программ и уметь их объяснить. Внести их в отчет с комментариями.
- •2. Выполнить два задания на двумерный массив по заданному номеру варианта и номеру, отсчитанному с конца.
- •3. Выполнить два задания на строки по заданному номеру варианта и номеру, отсчитанному с конца. Использовать в задачах два класса строк: String и StringBuilder.
- •4. Выполнить задание на применение регулярных выражений. Выбрать одно по заданному номеру.
- •Лабораторная работа 2 Тема: Структуры и перечисления как частные виды классов. Классы. Интерфейсы
- •[Атрибуты][модификаторы]enum имя_перечисления[: базовый класс] {список_возможных_значений}
- •[Атрибуты][модификаторы]struct имя_структуры [:список_интерфейсов] {тело_структуры}
- •Классы в c# [атрибуты][модификаторы]class имя_класса [:список_родителей] {тело_класса}
- •Индексаторы
- •Статические поля и методы класса
- •Наследование
- •Интерфейсы
- •Две стратегии реализации интерфейса
- •Преобразование к классу интерфейса
- •Проблемы множественного наследования
- •Коллизия имен
- •Ip1.Prop1("интерфейс iProps: свойство 1");
- •Ip1.Prop2("интерфейс 1 ", 88);
- •Ip2.Prop1("интерфейс iPropsOne: свойство1");
- •2. Наследование от общего предка
- •Обработка исключительных ситуаций
- •Блок finally
- •Лабораторная работа 3 Тема: Разработка gui. Создание sdi-приложений. Обработка событий
- •Создание простых форм с помощью комплекса инструментальных средств разработки программ .Net sdk
- •Режимы дизайна и кода
- •Элементы управления
- •Общие свойства, события и методы элементов управления
- •Обработка событий в Windows Forms
- •События MouseDown и Keypress
- •Форматирование элементов управления
- •Создание меню
- •Закрытие формы
- •Диалоговые окна
- •Создание панели инструментов
- •Список элементов ListBox
- •Потоковые классы
- •Встроенные типы данных и потоки
- •Класс File
- •Сериализация объектов
- •Создание многооконного приложения
- •Для каждого пункта меню пишем обработчики событий, выполняющие соответсвтвующие пункту действия. Перечисление MdiLayout
- •Вырезание, копирование и вставка текстовых фрагментов
- •Контекстное меню
- •Диалоговые окна
- •Сохранение файла при закрытии формы
- •OpenFileDialog и SaveFileDialog для sdi-приложений
- •Лабораторная работа 5 Тема: Создание и вывод графический изображений на форму. Анимация.
- •Класс Region
- •Вывод графических объектов без события Paint
- •Возможности класса Graphics
- •Класс Pen
- •Вывод изображений
- •Элемент управления PictureBox
- •Вывод изображений и двойная буферизация
Индексаторы
Метод-индексатор обеспечивает доступ к закрытому полю, представляющему массив. Объекты класса индексируются по этому полю. Синтаксически объявление индексатора - такое же, как и в случае свойств, но методы get и set приобретают аргументы по числу размерности массива, задающего индексы элемента, значение которого читается или обновляется. Важным ограничением является то, что у класса может быть только один индексатор и у этого индексатора стандартное имя this. Добавим в класс Person свойство children, задающее детей персоны, сделаем это свойство закрытым, а доступ к нему обеспечит индексатор:
// Программа 3. Индексаторы в класса на C#
…..
const int Child_Max = 10; //максимальное число детей
Person[] children = new Person[Child_Max];
int count_children=0; //число детей
public Person this[int i] { //индексатор
get {
if (i>=0 && i< count_children) return(children[i]);
else return(children[0]);
}
set {
if (i==count_children && i< Child_Max) {
children[i] = value; count_children++;
}
}
}
public void TestPersonChildren(){
Person pers1 = new Person(), pers2 = new Person();
pers1.Fam = "Петров"; pers1.Age = 42; pers1.Salary = 10000;
pers1[pers1.Count_children] = pers2;
pers2.Fam ="Петров"; pers2.Age = 21; pers2.Salary = 1000;
Person pers3= new Person("Петрова");
pers1[pers1.Count_children] = pers3;
pers3.Fam ="Петрова"; pers3.Age = 5;
Console.WriteLine ("Фам={0}, возраст={1}, статус={2}", pers1.Fam, pers1.Age, pers1.Status);
Console.WriteLine ("Сын={0}, возраст={1}, статус={2}", pers1[0].Fam, pers1[0].Age, pers1[0].Status);
Console.WriteLine ("Дочь={0}, возраст={1}, статус={2}", pers1[1].Fam, pers1[1].Age, pers1[1].Status);
}
Статические поля и методы класса
У класса могут быть поля, связанные не с объектами, а с самим классом. Эти поля объявляются как статические с модификатором static. Статические поля доступны всем методам класса. Независимо от того, какой объект вызвал метод, используются одни и те же статические поля, позволяя методу использовать информацию, созданную другими объектами класса.
Аналогично полям, у класса могут быть и статические методы, объявленные с модификатором static. Такие методы не используют информацию о свойствах конкретных объектов класса - они обрабатывают общую для класса информацию, хранящуюся в его статических полях.
Наследование
Повторное использование кода - это одна из главных целей ООП. Класс-потомок наследует все возможности родительского класса - все поля и все методы, открытую и закрытую часть класса. Правда, поля и методы родительского класса, снабженные атрибутом private, хотя и наследуются, но по-прежнему остаются закрытыми, и методы, создаваемые потомком, не могут к ним обращаться напрямую, а только через методы, наследованные от родителя. Единственное, что не наследует потомок - это конструкторы родительского класса. Конструкторы потомок должен создавать сам.
В C# разрешено только одиночное наследование, то есть у класса-потомка может быть только один родительский класс.
Рассмотрим класс, названный Found, играющий роль родительского класса. У него есть обычные поля, конструкторы и методы:
// Программа 4. Родительский класс Found
public class Found{
protected string name;
protected int credit;
public Found() { }
public Found(string name, int sum) {
this.name = name; credit = sum;
}
public virtual void VirtMethod() { //виртуальный метод
Console.WriteLine ("Отец: " + this.ToString() );
}
public override string ToString() { //переопределенный метод базового класса Object
return(String.Format("поля: name = {0}, credit = {1}", name, credit));
}
public void NonVirtMethod() {
Console.WriteLine ("Мать: " + this.ToString() );
}
public void Analysis() {
Console.WriteLine ("Простой анализ");
}
public void Work() {
VirtMethod();
NonVirtMethod();
Analysis();
}
}
Класс Found переопределил родительский метод класса Object ToString(), задав собственную реализацию возвращаемой методом строки, которая связывается с объектами класса. Как часто делается, в этой строке отображаются значения полей объекта данного класса. На переопределение родительского метода ToString() указывает модификатор метода override.
Класс Found закрыл свои поля для клиентов, но открыл для потомков, снабдив их модификатором доступа protected.
Создадим теперь класс Derived - потомка класса Found. Что же может делать потомок? Прежде всего, он может добавить новые свойства - поля класса. Заметьте, потомок не может ни отменить, ни изменить модификаторы или типы полей, наследованных от родителя - он может только добавить собственные поля.
Модифицируем наш класс Derived. Пусть он добавляет новое поле класса, закрытое для клиентов этого класса, но открытое для его потомков. protected int debet;
Конструкторы родителей и потомков
Каждый класс должен позаботиться о создании собственных конструкторов. Он не может в этом вопросе полагаться на родителя, поскольку, как правило, добавляет собственные поля, о которых родитель ничего не может знать. Конечно, если не задать конструкторов класса, то будет добавлен конструктор по умолчанию, инициализирующий все поля значениями по умолчанию. Но это редкая ситуация. Чаще всего, класс создает собственные конструкторы и, как правило, не один, задавая разные варианты инициализации полей.
public Derived(String^ name, int cred, int deb): Found (name,cred){}
Вызов конструктора родителя происходит не в теле конструктора, а в заголовке, пока еще не создан объект класса.
Добавление методов и изменение методов родителя
Потомок может добавлять новые собственные методы.
В отличие от неизменяемых полей классов - предков, класс - потомок может изменять наследуемые им методы. Если потомок создает метод с именем, совпадающим с именем метода предков, то возможны три ситуации:
перегрузка метода. Она возникает, когда сигнатура создаваемого метода отличается от сигнатуры наследуемых методов предков. В этом случае в классе потомка будет несколько перегруженных методов с одним именем, и вызов нужного метода определяется обычными правилами перегрузки методов;
переопределение метода. Метод родителя в этом случае должен иметь модификатор virtual или abstract. При переопределении сохраняется сигнатура и модификаторы доступа наследуемого метода;
скрытие метода. Если родительский метод не является виртуальным или абстрактным, то потомок может создать новый метод с тем же именем и той же сигнатурой, скрыв родительский метод в данном контексте. При вызове метода предпочтение будет отдаваться методу потомка, а имя наследуемого метода будет скрыто. Это не означает, что оно становится недоступным. Скрытый родительский метод всегда может быть вызван, если при вызове уточнить ключевым словом base. Имя_метода.
Метод потомка, скрывающий метод родителя, следует сопровождать модификатором new, указывающим на новый метод.
// Программа 4. Класс наследник с переопределенными методами родителя
public class Derived:Found {
protected int debet;
public Derived() {}
public Derived(String^ name, int cred, int deb): Found (name,cred){
debet = deb;
}
public void DerivedMethod(){ //новый метод потомка
Console.WriteLine("Это метод класса Derived");
}
new public void Analysis(){ //сокрытие метода родителя
base.Analysis();
Console.WriteLine("Сложный анализ");
}
public void Analysis(int level){ // перегрузка метода
base.Analysis();
Console.WriteLine("Анализ глубины {0}", level);
}
public override String^ ToString(){ //переопределение метода
return(String.Format("поля: name = {0}, credit = {1},debet ={2}",name, credit, debet));
}
public override void VirtMethod() { // переопределение метода родителя
Console.WriteLine ("Сын: " + this.ToString() );
} }
Статическое и динамическое связывание
Статическим связыванием называется связывание цели вызова и вызываемого метода на этапе компиляции, когда с сущностью связывается метод класса, заданного при объявлении сущности.
Динамическим связыванием называется связывание цели вызова и вызываемого метода на этапе выполнения, когда с сущностью связывается метод класса объекта, связанного с сущностью в момент выполнения.
В языке C# принята следующая стратегия связывания. По умолчанию предполагается статическое связывание. Для того чтобы выполнялось динамическое связывание, метод родительского класса должен снабжаться модификатором virtual или abstract, а его потомки должны иметь модификатор override.