Делегаты Action<T> и Func<T>

50

Вместо определения нового типа делегата с каждым типом параметра и возврата можно использовать делегаты Action<T> и Func<T>. Обобщенный делегат Action<T> предназначен для ссылки на метод, возвращающий void. Этот класс делегата существует в различных вариантах, так что ему можно передавать до 16 разных типов параметров.

Класс Action без обобщенного параметра предназначен для вызова методов без параметров, Action<in Т> — для вызова метода с одним параметром, Action<in T1, in Т2> — для вызова метода с двумя параметрами и Action<in T1, in Т2, in ТЗ, in Т4, in Т5, in Т6, in Т7, in Т8> — для вызова метода с восемью параметрами.

Делегаты Func<T> могут использоваться аналогичным образом. Func<T> позволяет вызывать методы с типом возврата. Подобно Action<T>, Func<T> определен в разных вариантах для передачи до 16 типов параметров и типа возврата. Func<out TResult> — тип делегата для вызова метода с типом возврата, но без параметров, Func<in T1, out TResult> — для метода с одним параметром, a Func<in T1, in T2, in ТЗ, in T4, out TResult> — для метода с четырьмя параметрами.

Давайте рассмотрим пример:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class ArrSort
    {
        // Реализуем обобщенный метод сортировки
        public static void Sort<T>(IList<T> sortArray, Func<T, T, bool> res)
        {
            bool mySort = true;
            do
            {
                mySort = false;
                for (int i = 0; i < sortArray.Count - 1; i++)
                {
                    if (res(sortArray[i + 1], sortArray[i]))
                    {
                        T j = sortArray[i];
                        sortArray[i] = sortArray[i + 1];
                        sortArray[i + 1] = j;
                        mySort = true;
                    }
                }
            } while (mySort);
        }
    }

    class UserInfo
    {
        public string Name { get; private set; }
        public string Family { get; private set; }
        public decimal Salary {get; private set;}

        public UserInfo(string Name, string Family, decimal Salary)
        {
            this.Name = Name;
            this.Family = Family;
            this.Salary = Salary;
        }

        // Переопределим метод ToString
        public override string ToString()
        {
            return string.Format("{0} {1}, {2:C}",Name,Family,Salary);
        }

        // Данный метод введен для соответствия сигнатуре 
        // делегата Func
        public static bool UserSalary(UserInfo obj1, UserInfo obj2)
        {
            return obj1.Salary < obj2.Salary;
        }
    }

    class Program
    {
        static void Main()
        {
            UserInfo[] userinfo = { new UserInfo("Dmitry","Medvedev",50000000000),
                                  new UserInfo("Alex","Erohin",100),
                                  new UserInfo("Alexey","Volkov",40000),
                                  new UserInfo("Wiley","Coyote",1000000)};

            ArrSort.Sort(userinfo, UserInfo.UserSalary);

            Console.WriteLine("Сортируем исходный объект по доходу: \n" +
                "-------------------------------------\n");
            foreach (var ui in userinfo)
                Console.WriteLine(ui);

            Console.ReadLine();
        }
    }
}
Использование специализированных делегатов
Пройди тесты
Лучший чат для C# программистов