
- •Делегаты
- •Передача делегатов в методы
- •Пример: решение алгебраических уравнений методом бисекции
- •static double F1(double x)
- •public delegate double Fun(double x); // объявление делегата class Test
- •Возможны и другие способы вызова:
- •Делегат может представлять несколько методов:
- •Реализация паттерна
- •Программисты часто используют одну и ту же схему организации и взаимодействия объектов в
- •Описание класса - источника:
- •Описание классов - наблюдателей:
- •Основная программа:
- •Для обеспечения обратной связи между наблюдателем и источником делегат объявлен с параметром типа
- •Возможные операции с делегатами
- •События
- •Событием может быть нажатие кнопки, выбор команды меню, завершение какой-либо операции и т.
- •События и делегаты
- •EventArgs является классом, базовым для всех классов параметров событий. Классы, производные от EventArgs,
- •Предположим, создается класс Clock, который с помощью события уведомляет классы-подписчики о том, что
- •Описание : public event TimeChangeHandler OnChange;
- •Пример «Симуляция и обработка события ButtonClick».
- •class Program {
Делегаты
•Делегат — это вид класса, предназначенный для хранения ссылок на методы. Т.е., делегат представляет метод (методы).
•Экземпляр делегата (как и любого другого класса) можно передать в качестве параметра, а затем вызвать инкапсулированный в нем метод.
•Делегаты используются для поддержки событий, а также как самостоятельная конструкция языка.
•Описание делегата задает сигнатуру методов, которые могут быть вызваны с его помощью:
[ атрибуты ] [ спецификаторы ] delegate тип имя([ параметры ])
Пример описания делегата:
public delegate void D ( int i );
Базовым классом делегата является класс System.Delegate
Передача делегатов в методы
Поскольку делегат является классом, переменную типа делегата можно передавать в методы в качестве параметра.
Таким образом обеспечивается функциональная параметризация: в метод можно передавать не только различные данные, но и различные функции их обработки. Функциональная параметризация применяется для создания универсальных методов
и обеспечения возможности обратного вызова.
Вкачестве простейшего примера универсального метода можно привести метод вывода таблицы
значений функции, в который передается диапазон значений аргумента, шаг его изменения и вид вычисляемой функции.

Пример: решение алгебраических уравнений методом бисекции
delegate double FUNC(double x); // представляет функцию y=F(x)
static double RootBis(FUNC f, double a, double b, double eps)
{
if (f(a) * f(b) > 0) return double.NaN; while (Math.Abs(b - a) >= eps)
{
double c = (a + b) / 2;
if (f(a) * f(c) > 0) a = c; else b = c;
}
return (a + b) / 2;

static double F1(double x)
{
return x * x - Math.Cos(x);
}
static double F2(double x)
{
return Math.Exp(x) - 1 / x;
}
static void Main()
{
FUNC myF = new FUNC(F1); Console.WriteLine(RootBis(myF, 0, 5, 1e-6)); myF = F2;
Console.WriteLine(RootBis(myF, 0, 5, 1e-6));
Console.WriteLine(RootBis(F1, 0, 5, 1e-6));
Console.ReadLine();
}

public delegate double Fun(double x); // объявление делегата class Test
{
public static void Table(string F_Name, Fun F, double x, double x_fin, double dx)
{
Console.WriteLine("\n Таблица функции " + F_Name); while (x <= x_fin)
{
Console.WriteLine("| {0,5:f1} | x += dx;
}
Console.WriteLine(" ---------------------
}
public static double Simple(double x) { static void Main()
{
Table("Sin", new Fun(Math.Sin), -2, 2, Table("Simple", new Fun(Simple), 0, 3,
}
}

Возможны и другие способы вызова:
{
Table("1", Simple, 0, 3, 1);
Table("2", Math.Sin, -2, 2, 0.5); // new Fun(Math.Sin)
Table("3", delegate(double 1);
}

Делегат может представлять несколько методов:
public delegate void Del(); // объявление делегата
class Program
{
public static void A() { Console.Write('A'); } public static void P() { Console.Write('P'); } static void Main(string[] args)
{
Del a = A, p = P, d = null; d += A; d += P; d += P; d();
Console.WriteLine(); d = p + a + p + a; d();
Console.ReadLine();
}
}
//вызов одного виртуального делегата (пула) приводит к вызову
//нескольких «привязанных» к нему методов
Реализация паттерна
«наблюдатель»
Рассмотрим применение делегатов для обеспечения связи между объектами по типу «источник —
наблюдатель».
Врезультате разбиения системы на множество совместно работающих классов появляется необходимость поддерживать согласованное состояние взаимосвязанных объектов. При этом для упрощения модификации кода желательно избежать жесткой связанности классов.
Для обеспечения связи между объектами во время выполнения программы применяется следующая стратегия. Объект, называемый источником, при изменении своего состояния, которое может представлять интерес для других объектов, посылает им уведомления. Эти объекты называются наблюдателями. Получив уведомление, наблюдатель опрашивает источник, чтобы синхронизировать с ним свое состояние.
Программисты часто используют одну и ту же схему организации и взаимодействия объектов в разных контекстах. За такими схемами закрепилось название
паттерны, или шаблоны проектирования. Описанная стратегия известна под названием паттерн «наблюдатель».
Наблюдатель (observer) определяет между объектами зависимость типа «один ко многим», т.е., при изменении состоянии одного объекта все зависящие от него объекты получают извещение
и автоматически обновляются.
Впримере котором демонстрируется схема оповещения источником трех наблюдателей (двух
классов). Гипотетическое изменение состояния объекта моделируется сообщением «Ух-ты!».
Описание класса - источника:
public |
delegate void Del(object o); // объявление делегата |
||
class Subj |
// класс-источник |
||
{ |
|
|
|
Del |
dels; |
// объявление экземпляра делегата |
|
(пула) |
|
|
|
// пока делегат (пул) пустой (==null) |
|||
int |
CountD = 0; |
// число делегатов в пуле |
|
public void Register(Del d) |
|||
{ |
|
// регистрация делегата d в пуле dels |
|
|
dels += d; |
// добавление делегата в конец пула |
|
|
CountD++; |
|
}
public void OPPA() // метод оповещения
{
Console.WriteLine(" ---------- |
Ух-ты!"); |
if (dels != null) dels(this); |
|
//запуск пула - оповещение наблюдателей,
//передаётся ссылка на источник (this)
}
public override string ToString()
{ return " источник с "+CountD+ " делегатами "; }
}