Сколько в классе может быть объявлено не статических конструкторов по умолчанию?
5. Чем отличаются конструкторы с аргументами от конструкторов по умолчанию?
6. Как инициализируются поля только для чтения?
7. Чем отличаются константы от полей только для чтения?
8. Сколько конструкторов с аргументами может быть объявлено в классе?
9. Сколько конструкторов по умолчанию может быть объявлено в классе?
10. Как осуществляется вызов конструкторов данного класса из других конструкторов?
11. Допустимо ли объявлять конструкторы со спецификациями protected и private?
Задания:
1. Выполнить приложения из примеров1-4. Проанализировать и объяснить работу приложений по примерам.
2. Создать приложение, в котором в цикле создается 10 объектов класса. Поля только для чтения каждого экземпляра равны порядковому номеру, отражающего очередность создания объектов.
3. Изменить тело конструктора с аргументами таким образом, чтобы производился анализ диапазона значения передаваемого аргумента. При выходе из некоторого диапазона - печаталось соответствующее сообщение, а значение аргумента приравнивалось, в зависимости от ситуации, минимально или максимально допустимому значению.
4. Объявить класс, содержащий два поля целого типа, свойства только для чтения этих полей, а также конструктор по умолчанию и конструктор с аргументами. Конструктор по умолчанию присваивает полям класса значение 2 и 3 соответственно. Конструктор с аргументами присваивает первому полю значение суммы аргументов, а второму полю значение разности аргументов. Создать объекты этого класса с использованием всех конструкторов. Аргументы для конструкторов вводятся с клавиатуры. Распечатать поля объектов.
5. Объявить класс, содержащий поле целого типа две константы, задающие допустимый диапазон значения этого поля и свойства для работы с этими полями. Конструктор с двумя аргументами присваивает полю значение суммы аргументов, если сумма не выходит за пределы диапазона, в противном случае, значение суммы ограничивается в соответствии с допустимым верхним или нижним значением. Создать объект этого класса. Аргументы для конструктора вводятся с клавиатуры. Распечатать поля объекта.
6. Объявить класс, содержащий одномерный целочисленный массив размерностью 10, индексатор для работы с этим массивом, а также конструктор по умолчанию и конструктор с одним аргументом. Конструктор по умолчанию присваивает элементам массива значение равное индексу элемента. Конструктор с аргументами присваивает элементам массива значение равное сумме аргумента с индексом элемента. Создать объекты этого класса с использованием всех конструкторов. Аргументы для конструктора вводятся с клавиатуры. Распечатать поля (массивы) объектов.
7. Объявить класс, содержащий одномерный целочисленный массив, индексатор для работы с этим массивом, а также приватный конструктор, принимающий один параметр в качестве аргумента. Конструктор выделяет память под массив, размерность которого определяется аргументом конструктора. Также в классе определен конструктор с двумя аргументами, который при своей работе вызывает приватный конструктор, передавая ему свой первый аргумент в качестве параметра, а затем расписывает все элементы массива значением своего второго аргумента. Создать объект этого класса. Ввести с клавиатуры элементы массива объекта Аргументы для конструктора вводятся с клавиатуры. Распечатать поля (массивы) объектов.
8. Объявить класс, содержащий одномерный целочисленный массив, а также функцию, для печати элементов этого массива. Конструктор класса принимает один параметр – ссылку на массив (внешний массив). Конструктор выделяет память под внутренний массив размерностью совпадающий с размерностью внешнего массива, затем значения элементов внешнего массива копирует во внутренний массив и сортирует внутренний массив по возрастанию. Класс также должен содержать поля readonly для минимального и максимального элемента массива. Значения этих полей определяются в результате работы конструктора. Создать объект этого класса. Элементы внешнего массива ввести с клавиатуры. Распечатать элементы массива объекта, минимальное и максимальное значение массива объекта.
9. Объявить класс, содержащий одномерный целочисленный массив, также функцию, для печати элементов этого массива. Конструктор класса принимает один параметр – ссылку на массив (внешний массив). Конструктор выделяет память под внутренний массив размерностью совпадающий с размерностью внешнего массива, затем значения элементов внешнего массива копирует во внутренний массив. Класс также должен содержать поля readonly для минимального и максимального элемента массива. Значения этих полей определяются в результате работы конструктора. Элементы внешнего массива ввести с клавиатуры. Создать объект этого класса . Распечатать элементы массива объекта, минимальное и максимальное значение массива объекта.
10. Объявить класс, содержащий одномерный целочисленный массив и функцию, для печати элементов этого массива. Конструктор класса принимает два параметра – ссылки на массивы (внешние массивы). Конструктор выделяет память под внутренний массив размерностью совпадающий с размерностью большего внешнего массива, затем формируются значения элементов внутреннего массива путем попарного суммирования соответствующих элементов внешних массивов. Недостающие элементы одного из массивов заменяются при суммировании нулями. Класс также должен содержать поля readonly для минимального и максимального элемента массива. Значения этих полей определяются в результате работы конструктора. Элементы внешних массивов ввести с клавиатуры. Создать объект этого класса. Распечатать элементы массива объекта, минимальное и максимальное значение массива объекта.
11. Объявить класс, содержащий одномерный целочисленный массив и функцию, для печати элементов этого массива. Конструктор класса принимает два параметра – ссылки на массивы (внешние массивы). Конструктор выделяет память под внутренний массив размерностью совпадающий с размерностью большего внешнего массива, затем формируются значения элементов внутреннего массива путем попарного сравнения соответствующих элементов внешних массивов и записи во внутренний массив наименьшего значения. Недостающие элементы одного из массивов заменяются при сравнении нулями. Класс также должен содержать поля readonly для минимального и максимального элемента массива. Значения этих полей определяются в результате работы конструктора. Элементы внешних массивов ввести с клавиатуры. Создать объект этого класса. Распечатать элементы массива объекта, минимальное и максимальное значение массива объекта.
12. Объявить класс, содержащий одномерный целочисленный массив размерностью 10, индексатор для работы с этим массивом. Создать объект данного класса. Ввести с клавиатуры элементы массива объекта. Найти элемент массива наиболее близкий по своему значению средне арифметическому значению элементов массива. Распечатать значение этого элемента и его индекс.
13. Объявить класс, содержащий одномерный целочисленный массив и функцию, для печати элементов этого массива. Конструктор класса принимает два параметра – ссылки на массивы (внешние массивы). Конструктор выделяет память под внутренний массив размерностью равной сумме размерностей внешних массивов, затем формируются значения элементов внутреннего массива путем копирования вначале элементов одного внешнего массивов, а затем второго. Результирующий массив сортируется. Класс также должен содержать поля readonly для минимального и максимального элемента массива. Значения этих полей определяются в результате работы конструктора. Элементы внешних массивов ввести с клавиатуры. Создать объект этого класса. Распечатать элементы массива объекта, минимальное и максимальное значение массива объекта
Лабораторная работа №4
Делегаты и события
По своей структуре делегат - это объект, который ссылается на метод.
С помощью делегата можно вызвать метод, на который он указывает.
В процессе выполнения программы делегату можно присвоить ссылку на другой метод. Это дает возможность определять во время выполнения программы, какой из методов должен быть вызван.
Делегаты реализуются как экземпляры классов, производных от библиотечного класса System.Delegate. Для создания делегата необходимо выполнит два шага.
На первом шаге необходимо объявить делегат. При этом сигнатура делегата должна полностью соответствовать сигнатуре метода, который он представляет.
Например, делегат должен ссылаться на статический метод класса СА:
static int min(int x,int y),
тогда объявление делегата может выглядеть, следующим образом:
delegate int LpFunc(int a,int b);
На втором шаге мы должны создать экземпляр делегата для хранения сведения о представляемом им методе:
LpFunc pfnk = new LpFunk(CA.min);
Экземпляр делегата может ссылаться на любой статический метод или метод объекта любого класса, при условии, что сигнатура метода полностью соответствует сигнатуре делегата.
Пример 1:
using System;
namespace ConsoleApplication14
{
class MathOprt
{
public static double Mul2(double val)
{
return val*2;
}
public static double Sqr(double val)
{
return val*val;
}
}
delegate double DblOp(double x);//объявление делегата
class Class1
{
static void Main(string[] args)
{
DblOp [] operation = // создание экземпляров делегата
{
new DblOp(MathOprt.Mul2),
new DblOp(MathOprt.Sqr)
};
for(int j=0;j<operation.Length;j++)
{
Console.WriteLine("Резльтаты операции[{0}]:",j);
Prc(operation[j], 4.0);
Prc(operation[j], 9.94);
Prc(operation[j], 3.143);
}
}
static void Prc(DblOp act, double val)
{
double rslt = act(val);
Console.WriteLine("Исходное значение {0}, результат {1}",
val,rslt);
}
}
}
Делегаты могут хранить несколько адресов областей памяти. То есть делегат может указывать на несколько различных методов. Это позволяет, последовательно инициализируя адреса вызывать метод за методом. Эта способность делегатов называется многоадресностью делегатов.
Для создания цепочки вызовов методов необходимо сначала создать экземпляр делегата для одного метода, а затем с помощью операции “ + = ” добавить остальные методы. В процессе выполнения кода можно не только добавлять новые методы, но и удалять не нужные с помощью операции ”- =”.
Методы, представляемые многоадресными делегатами должны возвращать значение void.
Перепишем код из примера 1 с применением многоадресного делегата.
Пример 2:
using System;
namespace ConsoleApplication14
{
class MathOprt
{
public static void Mul2(double val)
{
double rslt= val*2;
Console.WriteLine("Mul2 bсходное значение {0},результат {1}",
val,rslt);
}
public static void Sqr(double val)
{
double rslt = val*val;
Console.WriteLine("Sqr исходное значение {0}, результат {1}",
val,rslt);
}
}
delegate void DblOp(double x);//объявление делегата
class Class1
{
[STAThread]
static void Main(string[] args)
{
DblOp operations = new DblOp(MathOprt.Mul2);
operations += new DblOp(MathOprt.Sqr);
Prc(operations, 4.0);
Prc(operations, 9.94);
Prc(operations, 3.143);
}
static void Prc(DblOp act, double val)
{
Console.WriteLine("\n*********\n");
act(val);
}
}
}
События
Работа с событиями осуществляется в C# согласно модели «издатель-подписчик». Класс, ответственный за инициализацию (выработку) событий публикует событие, и любые классы могут подписаться на это событие. При возникновении события исполняющая среда уведомляет всех подписчиков о произошедшем событии, при этом вызываются соответствующие методы- обработчики событий подписчиков. Какой обработчик события будет вызван – определяется делегатом.
Платформа .NET требует для всех обработчиков событий следующей сигнатуры кода:
void OnRecChange(object source, ChangeEventArgs e)
{
// Код для обработки события
}
Обработчики событий обязательно имеют тип возвращаемого значения void. Обработчики событий принимают два параметра. Первый параметр _ это ссылка на объект, сгенерировавший событие. Эта ссылка передается обработчику самим генератором событий. Второй параметр – это ссылка на объект класса EventArgs или класса производного от него. В производном классе может содержаться дополнительная информация о событии.
Обработчик события определяется делегатом. Согласно сигнатуре обработчика события делегат должен принимать два параметра и выглядеть следующим образом:
public delegate void ChangeEventHandle(object source,ChangeEventArgs e);
Для того, чтобы иметь возможность подписаться на событие класс генератора событий должен содержать член типа указанного делегата с ключевым словом event и метод, который будет вызываться при возникновении события, например:
public event ChangeEventHandler OnChangeHandler;
Этот член является специализированной формой многообъектного делегата. Использую операцию “+=”, клиенты могут подписаться на это сообщение:
gnEvent.OnChangeHandler +=
new GenEvent.ChangeEventHandler (OnRecChange);
где gnEvent имя класса генератора событий.
Нижеследующий пример демонстрирует работу с событиями.
Пример№3:
using System;
namespace sobit
{
class ChangeEventArgs : EventArgs
{
string str;
public string Str
{
get
{
return str;
}
}
int change;
public int Change
{
get
{
return change;
}
}
public ChangeEventArgs(string str,int change)
{
this.str = str;
this.change = change;
}
}
class GenEvent // Генератор событий - издатель
{
public delegate void ChangeEventHandler
(object source,ChangeEventArgs e);
public event ChangeEventHandler OnChangeHandler;
public void UpdateEvent(string str,int change)
{
if(change==0)
return;
ChangeEventArgs e =
new ChangeEventArgs(str,change);
if (OnChangeHandler != null)
OnChangeHandler(this,e);
}
}
//Подписчик
class RecEvent
{
//Обработчик события
void OnRecChange(object source,ChangeEventArgs e)
{
int change = e.Change;
Console.WriteLine("Вес груза '{0}' был {1} на {2} тонны",
e.Str,change > 0 ? "увеличен" : "уменьшен",
Math.Abs(e.Change));
}
// в конструкторе класса осуществляется подписка
public RecEvent(GenEvent gnEvent)
{
gnEvent.OnChangeHandler += //здесь осуществляется подписка
new GenEvent.ChangeEventHandler(OnRecChange);
}
}
class Class1
{
[STAThread]
static void Main(string[] args)
{
GenEvent gnEvent = new GenEvent();
RecEvent inventoryWatch = new RecEvent(gnEvent);
gnEvent.UpdateEvent("грузовика", -2);
gnEvent.UpdateEvent("автопоезда", 4);
}
}
}
Вопросы:
1. Можно ли по сигнатуре объявления делегата определить сигнатуру функции, которую представляет делегат.
2. Какие ограничения накладываются на функции, которые может представлять многоадресный делегат?
3. Как включить или исключить заданную функцию из списка функций, представляемых многоадресным делегатом?
4. Как объявляется событие?
5. Что такое событие?
6. Чем отличается событие от многоадресного делегата?
7. Какова общепринятая сигнатура обработчика события?
8. Как осуществляется генерация события?
9. Каким образом обработчику события передается дополнительная информация о произошедшем событии?
10. Как осуществляется «подписка» на событие?
Задания:
1. Создать приложение, в котором генератор события “снабжает” событие следующей информацией: название поезда, время прибытия, номер вагона и места. Приемник события распечатывает эту информацию.
2. Создать приложение, в котором генератор события “снабжает” событие следующей информацией: название поезда, станция назначения, станция отправления и время в пути. Приемник события распечатывает эту информацию.
3. Создать приложение, в котором генератор события после генерации первого события генерирует последующие события только в том случае, если приемник события уведомляет, что сообщение принято (квитирование). Для квитирования использовать первый параметр обработчика события.
4. Создать приложение, в котором генератор события после генерации первого события генерирует только определенное количество событий. Количество генераций определяется путем уведомления со стороны приемника. Для уведомления использовать первый параметр обработчика события.
5. Создать приложение, в котором генератор события после генерации первого события генерирует последующие события только в том случае, если приемник события уведомляет, что событие принято (квитирование). Для квитирования использовать второй параметр обработчика события.
6. Создать приложение, в котором генератор события после генерации первого события генерирует только определенное количество событий. Количество генераций определяется путем уведомления со стороны приемника. Для уведомления использовать второй параметр обработчика события.
7. Создать приложение, в котором генератор события может генерировать три разных события. Приемники событий выступают в качестве абонентов почтового отделения и могут пересылать друг другу информацию, используя генератор в качестве почтового ящика. При этом они указывают номер (от 1 до 3) следующего приемника и некоторое целое число, которое передается получателю. Такой цикл передачи продолжается до тех пор, пока какой либо из приемников в качестве получателя не укажет номер ноль. В этом случае приложение завершает свою работу. При запуске приложения первое почтовое извещение всегда получает от генератора первый приемник. Для адресации и передачи информации использовать второй аргумент обработчика события.
8. Выполнить задание по пункту 7, но адресации и передачи информации использовать первый аргумент обработчика события.
9. Создать приложение, в котором генератор события, путем генерации одного события запрашивает у трех приемников некоторый ресурс. Каждый приемник сообщает, какое количество ресурса он может выделить. Для передачи информации использовать второй аргумент обработчика события.
10. Выполнить задание по пункту 9, но для передачи информации использовать первый аргумент обработчика события.
Лабораторная работа № 5