Литмир - Электронная Библиотека
A
A

// возвращает void и принимает единственный параметр типа Т.

public delegate void MyGenericDelegate<T>(T arg);

Как видите, в типе делегата

MyGenericDelegate<T>
определен единственный параметр, представляющий аргумент для передачи цели делегата. При создании экземпляра этого типа должно быть указано значение параметра типа наряду с именем метода, который делегат может вызывать. Таким образом, если указать тип
string
, тогда целевому методу будет отправляться строковое значение:

// Создать экземпляр MyGenericDelegate<T>

// с указанием string в качестве параметра типа.

MyGenericDelegate<string> strTarget = StringTarget;

strTarget("Some string data");

С учетом формата объекта

strTarget
метод
StringTarget
теперь должен принимать в качестве параметра единственную строку:

static void StringTarget(string arg)

{

  Console.WriteLine(

    "arg in uppercase is: {0}", arg.ToUpper());

}

Обобщенные делегаты Action<> и Func<>

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

1. Определить специальный делегат, соответствующий формату метода, на который он указывает.

2. Создать экземпляр специального делегата, передав имя метода в качестве аргумента конструктора.

3. Косвенно обратиться к методу через вызов

Invoke()
на объекте делегата.

В случае принятия такого подхода в итоге, как правило, получается несколько специальных делегатов, которые могут никогда не использоваться за рамками текущей задачи (например,

MyGenericDelegate&lt;T&gt;
,
CarEngineHandler
и т.д.). Хотя вполне может быть и так, что для проекта требуется специальный уникально именованный делегат, в других ситуациях точное имя типа делегата роли не играет. Во многих случаях просто необходим "какой-нибудь делегат", который принимает набор аргументов и возможно возвращает значение, отличное от
void
. В таких ситуациях можно применять встроенные в инфраструктуру делегаты
Action&lt;&gt;
и
Func&lt;&gt;
. Чтобы удостовериться в их полезности, создайте новый проект консольного приложения по имени
ActionAndFuncDelegates
.

Обобщенный делегат

Action&lt;&gt;
определен в пространствах имен
System
. Его можно использовать для "указания" на метод, который принимает вплоть до 16 аргументов (чего должно быть вполне достаточно!) и возвращает
void
. Вспомните, что поскольку
Action&lt;&gt;
является обобщенным делегатом, понадобится также указывать типы всех параметров.

Модифицируйте класс

Program
, определив в нем новый статический метод, который принимает (скажем) три уникальных параметра:

// Это цель для делегата Action&lt;&gt;.

static void DisplayMessage(string msg, ConsoleColor txtColor,

                           int printCount)

{

  // Установить цвет текста консоли.

  ConsoleColor previous = Console.ForegroundColor;

  Console.ForegroundColor = txtColor;

  for (int i = 0; i &lt; printCount; i++)

  {

    Console.WriteLine(msg);

  }

  // Восстановить цвет.

  Console.ForegroundColor = previous;

}

Теперь вместо построения специального делегата вручную для передачи потока программы методу

DisplayMessage()
вы можете применять готовый делегат
Action&lt;&gt;
:

Console.WriteLine(&quot;***** Fun with Action and Func *****&quot;);

<b>// Использовать делегат Action&lt;&gt; для указания на метод DisplayMessage().</b>

Action&lt;string, ConsoleColor, int&gt; actionTarget =

  DisplayMessage;

actionTarget(&quot;Action Message!&quot;, ConsoleColor.Yellow, 5);

Console.ReadLine();

Как видите, при использовании делегата

Action&lt;&gt;
не нужно беспокоиться об определении специального типа делегата. Тем не менее, как уже упоминалось, тип делегата
Action&lt;&gt;
позволяет указывать только на методы, возвращающие
void
. Если необходимо указывать на метод, имеющий возвращаемое значение (и нет желания заниматься написанием собственного типа делегата), тогда можно применять тип делегата
Func&lt;&gt;
.

Обобщенный делегат

Funс&lt;&gt;
способен указывать на методы, которые (подобно
Action&lt;&gt;
) принимают вплоть до 16 параметров и имеют специальное возвращаемое значение. В целях иллюстрации добавьте в класс
Program
новый метод:

// Цель для делегата Func&lt;&gt;.

static int Add(int x, int y)

{

  return x + y;

}

Ранее в главе был построен специальный делегат

BinaryOp
для "указания" на методы сложения и вычитания. Теперь задачу можно упростить за счет использования версии
Func&lt;&gt;
, которая принимает всего три параметра типа. Учтите, что последний параметр в
Func&lt;&gt;
всегда представляет возвращаемое значение метода. Чтобы закрепить данный момент, предположим, что в классе
Program
также определен следующий метод:

241
{"b":"847442","o":1}