Передача делегатов в методы

Поскольку делегат является классом, его можно передавать в методы в качестве параметра. Таким образом обеспечивается функциональная параметризация: в ме­тод можно передавать не только различные данные, но и различные функции их обработки. Функциональная параметризация применяется для создания универ­сальных методов и обеспечения возможности обратного вызова. В качестве простейшего примера универсального метода можно привести метод вывода таблицы значений функции, в который передается диапазон значений аргумента, шаг его изменения и вид вычисляемой функции. Этот пример приво­дится далее.

Обратный вызов (callback) представляет собой вызов функции, передаваемой в другую функцию в качестве параметра. Рассмотрим рис. 10.1. Допустим, в биб­лиотеке описана функция А, параметром которой является имя другой функции. В вызывающем коде описывается функция с требуемой сигнатурой (В) и переда­ется в функцию А. Выполнение функции А приводит к вызову В, то есть управле­ние передается из библиотечной функции обратно в вызывающий код.

Механизм обратного вызова широко используется в программировании. Напри­мер, он реализуется во многих стандартных функциях Windows. Пример передачи делегата в качестве параметра приведен в листинге 10.3. Про­грамма выводит таблицу значений функции на заданном интервале с шагом, равным единице.

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

using System;

namespace ConsoleApplication1

{

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

class Class1

{

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()

{

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

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

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

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

}

}

}

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

В среде Visual Studio 2005, использующей версию 2.0 языка С#, можно при­менять упрощенный синтаксис для делегатов. Первое упрощение заключается в том, что в большинстве случаев явным образом создавать экземпляр делегата не требуется, поскольку он создается автоматически по контексту. Второе упро­щение заключается в возможности создания так называемых анонимных мето­дов — фрагментов кода, описываемых непосредственно в том месте, где исполь­зуется делегат. В листинге 10.4 использованы оба упрощения для реализации тех же действий, что и листинге 10.3.

Листинг 10.4. Передача делегата через список параметров (версия 2.0)

using System;

namespace ConsoleApplication1

{

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

class Class1

{

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(" ");

}

static void Main()

{

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

Table(Math.Sin, -2, 2); // упрощение 1

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

Table(delegate(double x) { return 1; }, 0, 3); // упрощение 2

}

}

}

В первом случае экземпляр делегата, соответствующего функции Sin, создается автоматически1.

В результате в 2005 году язык С# в этой части вплотную приблизился к синтаксису ста­рого доброго Паскаля, в котором передача функций в качестве параметров была реализо­вана еще в 1992 году, если не раньше.

Чтобы это могло произойти, список параметров и тип возвра­щаемого значения функции должны быть совместимы с делегатом. Во втором случае не требуется оформлять простой фрагмент кода в виде отдельной функции Simple, как это было сделано в предыдущем листинге, — код функции оформля­ется как анонимный метод и встраивается прямо в место передачи. Альтернативой использованию делегатов в качестве параметров являются вирту­альные методы. Универсальный метод вывода таблицы значений функции можно реализовать с помощью абстрактного базового класса, содержащего два метода: метод вывода таблицы и абстрактный метод, задающий вид вычисляемой функции. Для вывода таблицы конкретной функции необходимо создать производный класс, переопределяющий этот абстрактный метод. Реализация метода вывода таблицы с помощью наследования и виртуальных методов приведена в листинге 10.5.

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

using System;

namespace ConsoleApplication1

{

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} |", х, F(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 Class1

{

static void Main()

{

TableFun a = new SinFun();

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

a.Table(-2, 2);

a = new SimpleFun();

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

a.Table(0, 3);

}

}

}

Результат работы этой программы такой же, как и предыдущей, но, на мой взгляд, в данном случае применение делегатов предпочтительнее.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: