Шрифт:
Интервал:
Закладка:
// возвращает 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<T>, CarEngineHandler и т.д.). Хотя вполне может быть и так, что для проекта требуется специальный уникально именованный делегат, в других ситуациях точное имя типа делегата роли не играет. Во многих случаях просто необходим "какой-нибудь делегат", который принимает набор аргументов и возможно возвращает значение, отличное от void. В таких ситуациях можно применять встроенные в инфраструктуру делегаты Action<> и Func<>. Чтобы удостовериться в их полезности, создайте новый проект консольного приложения по имени ActionAndFuncDelegates.
Обобщенный делегат Action<> определен в пространствах имен System. Его можно использовать для "указания" на метод, который принимает вплоть до 16 аргументов (чего должно быть вполне достаточно!) и возвращает void. Вспомните, что поскольку Action<> является обобщенным делегатом, понадобится также указывать типы всех параметров.
Модифицируйте класс Program, определив в нем новый статический метод, который принимает (скажем) три уникальных параметра:
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})// Это цель для делегата Action<>.
static void DisplayMessage(string msg, ConsoleColor txtColor,
int printCount)
{
// Установить цвет текста консоли.
ConsoleColor previous = Console.ForegroundColor;
Console.ForegroundColor = txtColor;
for (int i = 0; i < printCount; i++)
{
Console.WriteLine(msg);
}
// Восстановить цвет.
Console.ForegroundColor = previous;
}
Теперь вместо построения специального делегата вручную для передачи потока программы методу DisplayMessage() вы можете применять готовый делегат Action<>:
Console.WriteLine("***** Fun with Action and Func *****");
<b>// Использовать делегат Action<> для указания на метод DisplayMessage().</b>
Action<string, ConsoleColor, int> actionTarget =
DisplayMessage;
actionTarget("Action Message!", ConsoleColor.Yellow, 5);
Console.ReadLine();
Как видите, при использовании делегата Action<> не нужно беспокоиться об определении специального типа делегата. Тем не менее, как уже упоминалось, тип делегата Action<> позволяет указывать только на методы, возвращающие void. Если необходимо указывать на метод, имеющий возвращаемое значение (и нет желания заниматься написанием собственного типа делегата), тогда можно применять тип делегата Func<>.
Обобщенный делегат Funс<> способен указывать на методы, которые (подобно Action<>) принимают вплоть до 16 параметров и имеют специальное возвращаемое значение. В целях иллюстрации добавьте в класс Program новый метод:
// Цель для делегата Func<>.
static int Add(int x, int y)
{
return x + y;
}
Ранее в главе был построен специальный делегат BinaryOp для "указания" на методы сложения и вычитания. Теперь задачу можно упростить за счет использования версии Func<>, которая принимает всего три параметра типа. Учтите, что последний параметр в Func<> всегда представляет возвращаемое значение метода. Чтобы закрепить данный момент, предположим, что в классе Program также определен следующий метод:
- Понимание SQL - Мартин Грубер - Базы данных