Обобщенные делегаты Action и Func в C#
При использовании делегатов в приложениях требуется выполнить следующие шаги:
• Объявить тип делегата с сигнатурой соответствующего метода (с учетом типа возврата).
• Объявить экземпляр делегата с передачей имени метода в качестве аргумента конструктора;
• Выполнить групповое обращение к методам экземпляра делегата.
При таком подходе получается несколько оригинальных делегатов, которые не могут применяться в других приложениях. В некоторых случаях необходим просто делегат, принимающий набор аргументов и возвращающий или не возвращающий значение. В этих случаях можно воспользоваться встроенными делегатами Action<> и Func<>.
Обобщенный делегат Action<> можно применять для ссылки на метод, который принимает до 16 аргументов и не возвращает значение. Поскольку Action<> является обобщенным делегатом, требуется также указывать типы каждого параметра.
Теперь вместо объявления специального делегата вручную для передачи информации методу DisplayMessage () можно использовать готовый делегат Action<>, как показано ниже:
(Пример из книги Троелсена стр. 372)
class Program
{
// Это цель для делегата 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;
}
static void Main(string[] args)
{
Console.WriteLine("***** Fun with Action and Func *****");
// Использовать делегат Action() для указания на DisplayMessage.
Action<string, ConsoleColor, int> actionTarget =
new Action<string, ConsoleColor, int>(DisplayMessage);
actionTarget("ActionMessage!", ConsoleColor.Yellow, 5);
Console.ReadLine();
}
}
Если нужно указывать на метод с другим возвращаемым значением (и нет желания заниматься написанием собственного делегата), можно прибегнуть к делегату Func<>.
Обобщенный делегат Func<> может указывать на методы, которые (подобно Action<>) принимают вплоть до 16 параметров и имеют специальное возвращаемое значение.
В целях иллюстрации добавим следующий новый метод в класс Program:
// Цель для делегата Func<>.
static int Add(int x, int у)
{
return x + у;
}
Вывод будет иметь вид:
Синий цвет вместо желтого обусловлен тем, что представлен негатив консольного вывода.
Ранее в этой главе был построен специальный делегат BinaryOp для ссылки на методы сложения и вычитания. Теперь можно упростить задачу, воспользовавшись версией Func<>, которая принимает всего три параметра типа. Учтите, что последний в списке параметр типа Func<> — это всегда возвращаемое значение метода. Чтобы закрепить этот момент, предположим, что в классе Program также определен следующий метод:
static string SumToString(int x, int y)
{
return (x + y).ToString();
}
Теперь метод Main () может вызывать каждый из этих методов, как показано ниже:
class Program
{
// Цель для делегата Func<>.
static int Add(int x, int у)
{
return x + у;
}
static string SumToString(int x, int y)
{
return (x + y).ToString();
}
static void Main(string[] args)
{
Func<int, int, int> funcTarget = new Func<int, int, int>(Add);
int result = funcTarget.Invoke(40, 40);
Console.WriteLine("40 + 40 = {0}", result);
Func<int, int, string> funcTarget2 = new Func<int, int, string>(SumToString);
string sum = funcTarget2(90, 300);
Console.WriteLine(sum);
Console.ReadLine();
}
}
Делегаты Action<> и Func<> позволяют исключить объявление специального делегата, но следует ли их применять всегда. Это зависит от ситуации. Во многих случаях делегаты Action<> и Func<> будут предпочтительными. Если имя делегата лучше отражает предметную область, то предпочтительно объявление специального делегата.
Вставка (более четко о вызове Func Action)
Пусть Func имеет прототип
public static Т FirstOrDefault<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Тогда запись означает
p => p.dAw.StartsWith("М")
Первое p (перед =>) соответствует this IEnumerable<T> source,
и p.dAw.StartsWith("М") является предикатом
Соответственно прототипу
public static IEnumerable<S> Select<T, S>(
this IEnumerable<T> source,
Func<T, S> selector);
соответствует запись:
lst. Select(p => p)
Обобщенные делегаты Action и Func в C#
Лекции по предмету «Программирование»