306.29K
Category: programmingprogramming

Делегаты

1.

Делегирование — паттерн делегирования (Delegation) является
поведенческим (behavioral) паттерном проектирования. Это техника, в
которой объект выражает определенное поведение снаружи, но в реальности
делегирует ответственность за реализацию этого поведения связанному
объекту
В языках программирования делегат обычно представляется методом, хотя
на самом деле является классом • Экземпляр делегата (как и любого другого класса) можно передать в
качестве параметра, а затем вызвать инкапсулированный в нем метод.
• Делегаты используются для поддержки событий, а также как
самостоятельная конструкция языка.
• Описание делегата задает сигнатуру методов, которые могут быть
вызваны с его помощью:
[ атрибуты ] [ спецификаторы ] delegate тип имя([ параметры ])
Пример описания делегата:
public delegate void D ( int i );
Базовым классом делегата является класс System.Delegate

2.

C# делегаты
Делегаты подобны указателям на функцию. Их можно использовать для
вызова различных функций, причем выбор функции происходит во время
выполнения программы.
Делегат хранит имя метода, возвращаемый им тип и список параметров.
Делегат состоит из двух частей :
• Класс делегата
• Объект этого класса
После объявления класса делегата, создаются объекты этого класса. Эти
объекты используются для хранения и вызова методов, соответствующих
сигнатуре (тип возвращаемого значения и список параметров) метода
делегата.

3.

C# делегаты
Формализм:
[ур._ доступа] delegate возвр._ тип имя_класса_делегата
(тип_параметра имя_параметра, …..);
ур._ доступа - public, protected, и т.д.
возвр._ тип – тип возвращаемый делегатом
тип_параметра – тип передаваемого делегату параметра
Пример объявления делегата – все функции, попадающие под
это определение
public delegate double DelegCalc
(
double accel, double time
);

4.

C# делегаты
Использование. Объявляем класс
public class MoveCalc
{
public static double FSpeed ( double acc, double time)
{ // скорость
double speed = acc * time;
return(speed);
}
public static double Distance ( double acc, double time)
{// расстояние
double dist = acc * Math.Pow(time, 2);
return(dist);
}
}

5.

C# делегаты
class example
{
public void Main()
{
// Работаем с простыми делегатами
double accl = 10;
double time = 5;
// связываем с методом выч. скорости
DelegateCalc myDelegCalc = new DelegateCalc(MoveCalc.FSpeed);
double speed = myDelegCalc(accl, time); // используем
Console.WriteLine( " V = " +speed + " m / sec");
// теперь связываем с методом выч. расстояния
//DelegateCalc
myDelegCalc = new DelegateCalc(MoveCalc.Distance);
double dist = myDelegCalc(accl, time); // используем
Console.WriteLine(" Distance = " + dist + " m");
}
}

6.

C# делегаты
Многоадресные делегаты
Можно при помощи одного делегата вызывать разные методы.
Изменили - методы класса не возвращают значения, а выводят его на экран.
public delegate void DelegateCalcBig(double accel, double time);
public class MoveCalcBig
{
public static void FSpeed(double acc, double time)
{ // скорость
double speed = acc * time;
Console.WriteLine(" V = " + speed + " m / sec");
}
public static void Distance(double acc, double time)
{// выч. расстояния
double dist = acc * Math.Pow(time, 2);
Console.WriteLine(" Distance = " + dist + " m");
}
}

7.

C# делегаты
class Program
{
public void Main()
{
double accl_ = 100;
double time_ = 50; //далее заводим 2 объекта делегата
DelegateCalcBig myDelegCalcS = new DelegateCalcBig(MoveCalcBig.FSpeed);
DelegateCalcBig myDelegCalcL = new DelegateCalcBig(MoveCalcBig.Distance);
// создаем многоадресный делегат из двух предыдущих
// операция сложения перегружена для делегатов !!!
DelegateCalcBig myDelegCalcAll = myDelegCalcS + myDelegCalcL;
// используем многоадресный
myDelegCalcAll(accl_, time_);
}
}

8.

Возможные операции с делегатами
Обозначение [d1, d2, d3] подразумевает
комбинированный делегат, который
состоит из трёх простых именно в таком
порядке, т.е. при вызове сначала будет
вызван d1, потом d2, а затем d3.
Кроме оператора сложения, экземпляры
делегатов могут объединяться при
помощи
статического
метода
Delegate.Combine.
Операция вычитания также имеет
альтернативу в виде статического
метода Delegate.Remove.

9.

C# делегаты
Вызов методов объекта при помощи делегата
Можно с помощью делегатов вызывать и методы объектов, а не
только статические методы.
public delegate string DelegateDescr();
Этот делегат возвращает строку и не имеет параметров
Объявим 2 класса.
Первый описывает автомобиль, а второй - водителя

10.

public class Car
{
private string model;
private int speed;
public Car(string model, int speed)
{
this.model = model; this.speed = speed;
}
public string infocar()
{
return (" Модель = " +model + " Скорость =
+speed + " km / hour");
}
}
public class Driver
{
private string name;
private int age;
public Driver(string name, int age)
{
this.name = name; this.age = age;
}
public string infoperson()
{
return (name + " " +age + " лет ");
}
}
"

11.

C# делегаты
class Program
{
public static void Main()
{
Driver myDriver = new Driver("Vasia", 20);
DelegateDescr myDelelegateDescr = new
DelegateDescr(myDriver.infoperson);
string persinfo = myDelelegateDescr();
Console.WriteLine("person = " +persinfo);
Car myCar = new Car("Micro", 130);
myDelelegateDescr = new DelegateDescr(myCar.infocar);
string carinfo = myDelelegateDescr();
Console.WriteLine(" car = " +carinfo); }
}

12.

События
Событие — это элемент класса, предназначенный для организации
реакции объектов, использующих объект данного класса, на
различные ситуации, происходящие с этим объектом.
События позволят одному объекту посылать другим объектам
уведомления об изменении своего состояния. При этом для
объектов, являющихся наблюдателями события, активизируются
методы-обработчики этого события.
Обработчики должны быть зарегистрированы в объекте-источнике
события (в пуле). Таким образом, механизм событий формализует
на языковом уровне паттерн «наблюдатель».
Механизм событий можно также описать с помощью модели
«издатель-подписчик»: один класс, являющийся отправителем
(sender) сообщения, публикует события, которые он может
инициировать, а другие классы, являющиеся получателями
(receivers) сообщения, подписываются на получение этих событий.

13.

Событием может быть нажатие кнопки, выбор команды меню,
завершение какой-либо операции и т. п. Т.е., если происходит что-то
важное, программа должна отреагировать.
Порядок возникновения событий предсказать невозможно. Система
ждет возникновения события, а затем предпринимает действия по его
обработке. Метод, реагирующий на события, называется
обработчиком события (event handler).
В среде GUI любые элементы управления могут вызвать событие.
Например, если щелкнуть по кнопке, вызывается событие Click, а
если добавить элемент в раскрывающийся список, может быть
вызвано событие ListChanged. Реакция на событие является
предметом заботы других классов, и она совсем не интересует класс,
вызвавший событие. Реагировать должны обработчики случившегося
события.
В языке С# любой объект может опубликовать набор событий, а другие
классы могут на них подписаться. Когда публикующий класс
вызывает событие, все подписавшиеся классы уведомляются об этом.

14.

События и делегаты
Создание события в классе состоит из следующих частей:
• описание делегата, задающего сигнатуру обработчиков событий;
• описание события – элемента класса источника(издателя);
• описание метода (методов), инициирующих событие.
Класс-издатель определяет делегат, который должен быть
реализован классами-подписчиками. Когда возникает событие,
методы подписчиков вызываются через этот пул этого делегата.
Программист объявляет обработчик события как любой другой
делегат.
Существует соглашение, по которому обработчики событий в .NET
Framework возвращают void и принимают два параметра:
• Первый - это источник события, то есть объект-издатель.
• Вторым параметром передается объект, производный от класса
EventArgs.

15.

EventArgs является классом, базовым для всех классов
параметров событий. Классы, производные от EventArgs,
содержат информацию о возникшем событии.
Обычно достаточно базового класса EventArgs. Но, если с
событием связаны дополнительные атрибуты/параметры,
они указываются в классе производном от EventArgs.
Событие является свойством класса, опубликовавшего его.
Обработка события выполняется в классах-получателях
сообщения. Для этого в них описываются методыобработчики событий, сигнатура которых соответствует
типу делегата.
Каждый объект, желающий получать сообщение, должен
зарегистрировать в объекте-отправителе этот методобработчик.

16.

C# делегаты и события
Пусть некий вулкан генерирует событие о том что его температура
слишком высока – сейчас начнет извергаться. Обработчик события
выводит об этом сообщение.
Объявим событие OnEruption, использующее класс делегата EruptionHandler
// Классы, наследники EventArgs, содержат инфу о возникшем событии –
// объявляем первым!
public class EruptionEventArgs : EventArgs
{
private string message;
public EruptionEventArgs(string message)
{
this.message = message;
}
public string Message
// свойство для получения поля message
{
get { return message; }
}
};

17.

//Создадим класс вулкана и затем добавим к нему событие
public class Vulcan //класс вулкана-виновника
{
private string name;// и что же это за вулкан?
private int temperature; // температура в вулкане
public Vulcan(string name)
{
this.name = name;
}
public int Temperature
{
//свойство для установки температуры
set
{
temperature = value;
}
}
}

18.

Определим связанный класс делегата для вулкана
public delegate void EruptionHandler(object vulcan, EruptionEventArgs
EEA);
Все делегаты, вызывающие обработчики событий, должны возвращать void
и принимать 2 параметра. Первый – должен иметь тип object и
представлять объект вызвавший событие. Второй параметр – объект
класса, унаследованного от System.EventArgs.
Для аргумента EruptionEventArgs надо определить свой класс
public class EruptionEventArgs : EventArgs
{
private string message;
public EruptionEventArgs(string message)
{
this.message = message;
}
public string Message
{
get { return message; }
}
};

19.

Тогда полный код класса вулкан будет таким:
public class Vulcan //класс вулкана-виновника
{
private string name;// и что же это за вулкан?
private int temperature; // температура в вулкане
//класс делегата для обработки события
public delegate void EruptionHandler(object vulcan, EruptionEventArgs EEA);
// объявление события
public event EruptionHandler onEruption;
public Vulcan(string name) { this.name = name; }
public int Temperature //свойство для установки температуры
{set
{
temperature = value;
if (temperature > 1000)
{
EruptionEventArgs myEEA = new EruptionEventArgs("Вулкан " + name + " дымит");
onEruption(this, myEEA);
}
else if (temperature > 10000)
{
EruptionEventArgs myEEA = new EruptionEventArgs("Вулкан "+name+" извергается");
onEruption(this, myEEA);
}
}
}
}

20.

C# делегаты
В проверке на температуру создается объект, который будет аргументом для события с
именем myEEA. Строка о извержении присваивается полю message этого объекта.
Затем генерируется событие onEruption. Этому событию передаёт объект класса
Vulcan ( при помощи ссылки this) и объект – аргумент события myEEA
Событие onEruption может быть отслежено и из любого другого объекта, который
будет способен его обрабатывать. Например объявим класс VulcanMonitor, объект
которого будет использоваться для отслеживания событий объекта класса Vulcan
public class VulcanMonitor
{
public VulcanMonitor(Vulcan myVulcan)
{
myVulcan.onEruption +=
new Vulcan.EruptionHandler(DisplayMessage);
}
public void DisplayMessage(object myVulcan,
EruptionEventArgs myEEA)
{
Console.WriteLine(myEEA.Message);
}
}

21.

C# делегаты
Конструктор класса VulcanMonitor принимает параметр типа Reactor c
именем myVulcan. Этот параметр есть ссылка на объект, для которого
будет отслеживаться событие onEruption. Отслеживание события
обеспечивается привязкой переданного параметра к обработчику
EruptionHandler. Это в конструкторе записано так
myVulcan.onEruption +=
new Vulcan.EruptionHandler( DisplayMessage);
Когда объект myVulcan сгенерирует событие onEruption , то для его
обработки будет вызван метод DisplayMessage().
Ранее класс EruptionHandler был определен как делегат, возвращающий
значение void и принимающий два параметра – объект типа object и объект
типа onEruptionEventArgs. Это в точности соответствует сигнатуре метода
DisplayMessage()

22.

C# делегаты
class ExampleEvent
{
public void Mains()
{
Vulcan myVulcan = new Vulcan("Этна");
// вулкан
// наблюдатель за оным
VulcanMonitor myVulcanMonitor = new VulcanMonitor(myVulcan);
Console.WriteLine(" T = 500");
myVulcan.Temperature = 500; // генерации нет
Console.WriteLine(" T = 2500");
myVulcan.Temperature = 2500;
// генерируется событие OnEruption, объект myVulcanMonitor
// замечает это событие и вызывает метод DisplayMessage()
Console.WriteLine(" T = 25000");
myVulcan.Temperature = 25000;
// генерируется событие OnEruption, объект myVulcanMonitor
// замечает это событие и вызывает метод DisplayMessage()
}
}
English     Русский Rules