Приветствую всех, сегодня хочу еще раз поговорить о делегатах. Давайте вспомним что такое делегат. По сути, это объект, который хранит ссылку на некий метод, и может этот метод вызвать при необходимости. Точнее мы можем вызвать метод через этот объект. И особенность использования делегатов в том, что при объявлении ссылки на объект-делегат мы можем и не знать, на какой конкретно метод, будет ссылаться этот объект. Мы только знаем, что целевой метод должен иметь определенного вида список параметров и тип возвращаемого значения.
Для создания делегата, нужно сначала определить его тип. Как и в случае классов, мы создаем некий шаблон, в соответствии с которым, буде в дальнейшем создавать конкретные экземпляры. Тип делегата определяется по следующему правилу:
delegate тип_значения ИмяТипаДелегата(список_параметров);
Как видите, объявление типа делегата, отчасти, похоже на объявление метода, но в самом начале, указывается ключевое слово delegate, а после списка аргументов, нет тела как у метода, вместо которого ставит символ «;».
Обратите внимание, объект-делегат может ссылаться только на такие методы, чья сигнатура (список параметров и тип возвращаемого значения, в данном контексте) полностью совпадает с объявлением типа этого делегата. Но ссылаться делегат может как на статические, так и на обычные методы классов.
Пример:
/Объявляем делегат, по сути - тип делегатов
delegate double DoubleDelegat(double aFirstArg, double aSecondArg);
//Основной класс программы
class Program
{
//Статический метод, возвращающий сумму двух аргументов
static double Sum(double aFirstSumArg, double aSecondSumArg)
{
return aFirstSumArg + aSecondSumArg;
}
//Главный метод программы (точка входа)
static void Main(string[] args)
{
//Создаем экземпляр делегата DoubleDelegat (ссылающийся на метод Sum)
DoubleDelegat sumDelegat = new DoubleDelegat(Sum);
}
}
Как видите, создание делегата очень похоже на создание обычного объекта, но при создании объекта-делегата, мы указываем метод, на который ссылается делегат. В данном случае, это метод «Sum». А вызов метода происходит следующим образом:
//Вызов метода Sum через делегат sumDelegat double sumResult = sumDelegat(24.5, 21.4);
//Объявляем делегат, по сути - тип делегатов
delegate double DoubleDelegat(double aFirstArg, double aSecondArg);
//Основной класс программы
class Program
{
//Статический метод, возвращающий сумму двух аргументов
static double Sum(double aFirstSumArg, double aSecondSumArg)
{
return aFirstSumArg + aSecondSumArg;
}
//Статический метод, возвращающий разность двух аргументов
static double Sub(double aFirstSumArg, double aSecondSumArg)
{
return aFirstSumArg - aSecondSumArg;
}
//Главный метод программы (точка входа)
static void Main(string[] args)
{
//Создаем экземпляр делегата DoubleDelegat (ссылающийся на метод Sum)
DoubleDelegat sumDelegat = new DoubleDelegat(Sum);
//Вызов метода Sum через делегат sumDelegat
double sumResult = sumDelegat(24.5, 21.4);
//Вывод результата в консоль
Console.WriteLine("Результат работы sumResult с методом Sum: " + sumResult);
//Создаем экземпляр делегата DoubleDelegat (ссылающийся на метод Sum)
DoubleDelegat subDelegat = new DoubleDelegat(Sub);
//Вызов метода Sum через делегат sumDelegat
double subResult = subDelegat(24.5, 21.4);
//Вывод результата в консоль
Console.WriteLine("Результат работы subResult с методом Sub: " + subResult);
}
}
Таким образом, можно сделать вывод, что при объявлении типа делегата, мы указываем только прототип методов, которые этот делегат может вызывать, а что эти методы будут делать, мы можем даже не догадываться.
Давайте сразу рассмотрим фрагмент кода, в котором представлено объявление типа делегатов и класс, описывающий объекты-коллекции:
//Делегат, для использования в классе DoubleCollection
delegate double DoubleOperation(double anAgr);
//Коллекция элементов типа double
class DoubleCollection
{
//Добавляет элемент в коллекцию
public void Add(double anItem)
{
collection.Add(anItem);
}
//Удаляет элемент из коллекции (по индексу)
public void RemoveAt(int anIndex)
{
collection.RemoveAt(anIndex);
}
//Вызывает метод, на который ссылается делегат для всех элементов коллекции
public void DoOperation()
{
//Если делегат задан
if (operation != null)
{
//Перебрать все элементы коллекции
for (int i = 0; i < collection.Count; i++)
{
//Выполнить операцию над текущим элементом
collection[i] = operation(collection[i]);
}
}
}
//Устанавливает или возвращает значение делегата operation
public DoubleOperation Operation
{
get { return operation; }
set { operation = value; }
}
//Индексатор (возвращает или устанавливает значение элемента по индексу)
public double this[int anIndex]
{
get { return collection[anIndex]; }
set { collection[anIndex] = value; }
}
//Возвращает количество элементов
public int Count
{
get
{
return collection.Count;
}
}
//Хранилище элементов
private List<double> collection = new List<double>();
//Делегат, для хранения ссылки на метод, который укажет пользователь класса
private DoubleOperation operation = null;
}
В начале программы объявляется тип делегатов DoubleOperation, делегаты такого типа ссылаются на методы, принимающие один аргумент типа double и возвращающие значение такого же типа. В классе DoubleCollection объявляется поле operation, которое является ссылкой на делегат, типа DoubleOperation. Значение полю operation задается через свойство Operation . Рассмотрим подробнее код метода DoOperation:
//Вызывает метод, на который ссылается делегат для всех элементов коллекции
public void DoOperation()
{
//Если делегат задан
if (operation != null)
{
//Перебрать все элементы коллекции
for (int i = 0; i < collection.Count; i++)
{
//Выполнить операцию над текущим элементом
collection[i] = operation(collection[i]);
}
}
}
В данном методе, перебираются все элементы коллекции, и над каждым выполняется вызов метода, на который ссылается делегат operation .
//Основной класс программы
class Program
{
//Возвращает значение операнда, увеличенное на 13 процентов
static double SomeOperation(double aValue)
{
return aValue * 1.13;
}
//Главный метод программы
static void Main(string[] args)
{
//Создание коллекции
DoubleCollection someCollection = new DoubleCollection();
//Добавление в неё элементов
someCollection.Add(124.4);
someCollection.Add(120.8);
someCollection.Add(118.1);
someCollection.Add(128.9);
someCollection.Add(111.3);
//Создание делегата на основе метода SomeOperation и присваивание его коллекции
someCollection.Operation = new DoubleOperation(SomeOperation);
//Выполнение операции
someCollection.DoOperation();
//Вывод результата в консоль
for (int i = 0; i < someCollection.Count; i++)
Console.WriteLine(someCollection[i]);
}
}
Пользователю класса DoubleCollection нужно просто позаботиться о создании метода SomeOperation который мог бы делать и какие-то другие действия.

Всем привет друзья. Я не понял. Зачем Мне делегать чтобы вызвать два разных статических метода разница и сумма. В чем проблема взять и не вызвать метод и передать туда нужные параметры?
Так как делегаты упрощают работу, сокращая код. Вы можете выстроить цепочку из методов с помощью делегатов, и вызвать по необходимости. Так же можно применять делегаты в качестве аргументов, приведу пример, у вас метод может работать с большим набором данных, которые он должен обработать внутри себя. Вы можете поочередно вызывать методы, а можете одним делегатом передать как аргумент и обработать внутри метода, что сократит код в несколько десятков строк кода, и повысит производительность. Что бы понять преимущества делегатов надо смотреть примеры.