Оскільки делегат є класом, його можна передавати в методи як параметр. Цим забезпечується функціональна параметризація: у метод можна передавати не тільки різні дані, але і різні функції їх обробки. Функціональна параметризація застосовується для створення універсальних методів і забезпечення можливості зворотного виклику.
Як універсальний метод можна привести метод виведення таблиці значень функції. У метод передається діапазон значень аргументу, крок його зміни і вид обчислюваної функції. Цей приклад наводиться далі.
Зворотним викликом (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);
}
}
}
Результат роботи цієї програми такий же, як і попередньої, але в даному випадку застосування делегатів переважно.