Делегаты – способ именования сигнатуры метода. Делегаты предназначены для передачи методов другим методам. Если требуется передавать методы в качестве параметров, сведения о методе необходимо поместить в новый тип объекта – делегат. Делегаты содержат информацию о методе.
public delegate void VoidOperation(uint x);
Определили делегат VoidOepration и указали, что каждый экземпляр этого делегата может содержать сведения о методе, принимающем один параметр uint и возвращающем void. Синтаксис аналогичен тому, что используется при определении методов, за исключением того, что отсутствует тело метода, а определение предваряется ключевым словом delegate.
Определив делегата, мы можем создать его экземпляр и использовать его для хранения сведений о конкретном методе.
Пример использования:
int x = 40; GetString first = new GetString(x.ToString); Console.WriteLine(first()); // эквивалентен WriteLine(x.ToString());
В этом коде мы создали экземпляр делегата типа GetString и инициализировали его таким образом, что он стал ссылаться на метод ToString() целочисельной переменной х. Делегаты в C# всегда синтаксически принимают конструктор с одним параметром, в качестве параметра передается метод на который будет ссылаться делегат. Сигнатура входного метода (параметра) должна соответствовать сигнатуре, указанной при объявлении делегата, иначе возникает ошибка при компиляции.
В любом коде указание имени делегата с последующими скобками, в которых перечислены параметры, имеет точно такое же действие, что и вызов метода, для которого делегат служит оболочкой.
Делегат – это объект, хранящий указатель на функцию (исполнимый код) и способный вызвать его на выполнение. Так бы выглядел код на С++ (void EntryPoint()-) метод, в котором исполняется поток.
Thread NewThread = new Thread(); Thread.Start(EntryPoint);
Объекты делегаты являются наседниками класса System.Delegate, они позволяют менять значение указателя непосредственно во время работы программы (фактически, динамически вызывать разные функции) и способны хранить одновременно несколько указателей на разные функции (+, +=). Компилятор не позволит применить операции (+, +=) для совмещения нескольких методов в одном делегате если метод, на который он ссылается возвращает не значение void.
Currency c = new Currency(); delegates d1 = new delegates(c.fun); delegates d2 = new delegates(c.fun4); delegates d3 = new delegates(c.fun4); d3 = d3 + d1; // d3 содержит вызовы fun4 + fun d3 += d2; // d3 содержит вызовы fun4 + fun + fun4 d3(5, ref x); // произойдет цепочка вызовов
Если список ссылок на функции в делегате пуст, то при попытке обращения к нему возникает исключительная ситуация System.NullReferenceException. Ошибки во время работы программы также возникнут если из списка удаляется (-, -=) не существующая в нем функция или удаление выпоняется по отношению к пустому списку.
Использование делегатов. Пример
private delegate void delegates(int n, ref double x); public class MathOperations { public static double Multiply(double value) {return value * 2; } public static double Square(double value) {return value * value; } public static double Quadre(double value) {return value * value * value; } } public static void Main() { DoubleFun[] operations = new DoubleFun[3]; // 3 функциии operations[0] = new DoubleFun(MathOperations.Multiply); operations[1] = new DoubleFun(MathOperations.Square); operations[2] = new DoubleFun(MathOperations.Quadre); for (int i = 0; i < operations.Length; i++) { Console.WriteLine("Выпоняю операцию {0}:", i); Console.WriteLine(operations[i](2.0)); Console.WriteLine(operations[i](7.94)); Console.WriteLine(operations[i](1.414)); } }
В этом коде мы создаем массив делегатов DoubleFun, каждый элемент массива инициализируется ссылкой на отдельные операции, реализованные в классе MathOperations. Затем в цикле проходим по массив, применяя каждую операцию к трем отдельным значениям. Это один из способов применения делегатов: их можно группировать в массив, а несколько методов можно вызвать в цикле.