Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие КНЕУ.doc
Скачиваний:
24
Добавлен:
07.03.2016
Размер:
3.9 Mб
Скачать

10.1.4. Операції

Делегати можна порівнювати на рівність і нерівність. Два делегати рівні, якщо вони обидва не містять посилань на методи або якщо вони містять посилання на одні і ті ж методи в одному і тому ж порядку. Порівнювати можна навіть делегати різних типів за умови, що вони мають один і той же тип повертаємого значення і однакові списки параметрів.

Делегати, які розрізняються тільки іменами, вважаються за тих, які мають різні типи.

З делегатами одного типу можна виконувати операції простого і складного привласнення, наприклад:

Del d1 = new Del (o1.Do): // o1.Do

Del d2 = new Del (o2.Do); // o2.Do

Del d3 = d1 + d2; // ol.Do і o2.Do

d3 += d1; // ol.Do. o2.Do і ol.Do

d3 -= d2; // o1.Do і ol.Do

Ці операції можуть знадобитися, наприклад, в тому випадку, якщо в різних обставинах потрібно викликати різні набори і комбінації наборів методів.

Делегат, як і рядок string, є незмінним типом даних, тому при будь-якій зміні створюється новий екземпляр, а старий згодом видаляється складальником сміття.

10.1.5. Передача делегатів в методи

Оскільки делегат є класом, його можна передавати в методи як параметр. Цим забезпечується функціональна параметризація: у метод можна передавати не тільки різні дані, але і різні функції їх обробки. Функціональна параметризація застосовується для створення універсальних методів і забезпечення можливості зворотного виклику.

Як універсальний метод можна привести метод виведення таблиці значень функції. У метод передається діапазон значень аргументу, крок його зміни і вид обчислюваної функції. Цей приклад наводиться далі.

Зворотним викликом (callback) є виклик функції, яка передається в іншу функцію як параметр. Розглянемо рис. 10.1. Допустимо, в бібліотеці описана функція А, параметром якої є ім'я іншої функції. У коді описується функція з необхідною сигнатурою (В) і передається у функцію А. Виконання функції А приводить до виклику В, тобто управління передається з бібліотечної функції назад в код.

Рис. 10.1. Механізм зворотного виклику

Механізм зворотного виклику широко використовується в програмуванні. Наприклад, він реалізується в багатьох стандартних функціях Windows.

Приклад передачі делегата як параметр приведений в лістингу 10.3. Програма виводить таблицю значень функції на заданому інтервалі з кроком, рівним одиниці.

Лістинг 10.3. Передача делегата через список параметрів

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace examp67

{

public delegate double Fun( double x ); // оголошення делегата

class Classl

{

public static void Table (Fun F, double x, double b )

{

Console.WriteLine( " X Y " );

while (x <= b)

{

Console.WriteLine("| {0,8:0.000} | {1,8:0.000}", x, F(x));

x += 1;

}

Console.WriteLine( " ....................." );

}

public static double Simple(double x)

{

return 1;

}

static void Main(string[] args)

{

Console.WriteLine("Таблиця функції Sin");

Table(new Fun( Math.Sin), -2, 2 );

Console.WriteLine(" Таблиця функції Simple " );

Table( new Fun(Simple), 0, 3 );

}

}

}

Результат роботи програми:

Таблиця функції Sin

-------X ------- Y --------

I -2.000 I -0,909 I

I -1.000 I -0,841 I

I 0.000 I 0,000 I

I 1,000 I 0.841 I

I 2,000 I 0,909 I

-------------------------------

Таблиця функції Simple

-------X ------- Y -------

I 0.000 I 1,000 I

I 1.000 I 1,000 I

I 2.000 I 1,000 I

I 3.000 I 1,000 I

-------------------------------

Має місце спрощений синтаксис для делегатів. Перше спрощення полягає в тому, що в більшості випадків явним чином створювати екземпляр делегата не потрібно, оскільки він створюється автоматично по контексту. Друге спрощення полягає в можливості створення так званих анонімних методів - фрагментів коду, що описуються безпосередньо в тому місці, де використовується делегат. У лістингу 10.4 використано обидва спрощення для реалізації тих же дій, що і лістингу 10.3.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace examp68

{

public delegate double Fun(double x); // об’ява делегата

class Classl

{

public static void Table(Fun F, double x, double b)

{

Console.WriteLine(" X Y ");

while (x <= b)

{

Console.WriteLine("| {0,8:0.000} | {1,8:0.000}", x, F(x));

x += 1;

}

Console.WriteLine(" .....................");

}

public static double Simple(double x)

{

return 1;

}

static void Main(string[] args)

{

Console.WriteLine(" Таблиця функції Sin ");

Table(Math.Sin, -2, 2);

Console.WriteLine(" Таблиця функції Simple ");

Table(delegate(double x){return 1;}, 0, 3);

}

}

}

У першому випадку екземпляр делегата, відповідного функції Sin, створюється автоматично. Щоб це могло відбутися, список параметрів і тип повертаємого значення функції мають бути сумісні з делегатом. У другому випадку не потрібно оформляти фрагмент коду у вигляді окремої функції Simple, як це було зроблено в попередньому лістингу, - код функції оформляється як анонімний метод і вбудовується прямо в місце передачі.

Альтернативою використанню делегатів як параметрів є віртуальні методи. Метод виведення значень функції у вигляді таблиці можна реалізувати за допомогою абстрактного базового класу. Він містить два методи: метод виведення таблиці і абстрактний метод, для обчислення функції. Для виведення таблиці конкретної функції необхідно створити похідний клас, який перевизначає цей абстрактний метод. Реалізація методу виведення таблиці за допомогою спадкоємства і віртуальних методів приведена в лістингу 10.5.

Листинг 10.5. Альтернатива параметрам-делегатам

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace examp69

{

abstract class TableFun

{

public abstract double F(double x );

public void Table(double x, double b )

{

Console.WriteLine( " X Y " );

while ( x <= b )

{

Console.WriteLine(" {0,8:0.000} | {1,8:0.000} |", x, F(x));

x+=1;

}

Console.WriteLine( " ....................." );

}

}

class SimpleFun : TableFun

{

public override double F( double x ) {

return 1;

}

}

class SinFun : TableFun

{

public override double F( double x )

{

return Math.Sin(x);

}

}

class Classl

{

static void Main()

{

TableFun a = new SinFun();

Console.WriteLine(" Таблица функции Sin " );

a.Table(-2, 2 );

a = new SimpleFun();

Console.WriteLine(" Таблица функции Simple " );

a.Table(0,3);

}

}

}

Результат роботи цієї програми такий же, як і попередньої, але в даному випадку застосування делегатів переважно.