Учебники

C # — делегаты

Делегаты C # аналогичны указателям на функции в C или C ++. Делегат — это переменная ссылочного типа, которая содержит ссылку на метод. Ссылка может быть изменена во время выполнения.

Делегаты особенно используются для реализации событий и методов обратного вызова. Все делегаты неявно являются производными от класса System.Delegate .

Объявление делегатов

Объявление делегата определяет методы, на которые может ссылаться делегат. Делегат может ссылаться на метод, который имеет ту же подпись, что и подпись делегата.

Например, рассмотрим делегата —

public delegate int MyDelegate (string s);

Предыдущий делегат может использоваться для ссылки на любой метод, который имеет единственный строковый параметр и возвращает переменную типа int .

Синтаксис для объявления делегата —

delegate <return type> <delegate-name> <parameter list>

Выездные делегаты

После того, как тип делегата объявлен, объект делегата должен быть создан с новым ключевым словом и связан с определенным методом. При создании делегата аргумент, передаваемый новому выражению, записывается аналогично вызову метода, но без аргументов метода. Например —

public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

В следующем примере демонстрируется объявление, создание экземпляра и использование делегата, который можно использовать для ссылки на методы, которые принимают целочисленный параметр и возвращают целочисленное значение.

Live Demo

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl {
   
   class TestDelegate {
      static int num = 10;
      
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         
         //calling the methods using the delegate objects
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         nc2(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —

Value of Num: 35
Value of Num: 175

Многоадресная рассылка делегата

Делегировать объекты можно с помощью оператора «+». Составной делегат вызывает двух делегатов, из которых он был составлен. Только делегаты одного типа могут быть составлены. Оператор «-» может использоваться для удаления делегата компонента из составного делегата.

Используя это свойство делегатов, вы можете создать список вызовов методов, которые будут вызываться при вызове делегата. Это называется многоадресной передачей делегата. Следующая программа демонстрирует групповое вещание делегата —

Live Demo

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl {
   class TestDelegate {
      static int num = 10;
      
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         
         nc = nc1;
         nc += nc2;
         
         //calling multicast
         nc(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —

Value of Num: 75

Использование делегатов

В следующем примере демонстрируется использование делегата. Делегат printString может использоваться для ссылки на метод, который принимает строку в качестве входных данных и ничего не возвращает.

Мы используем этот делегат для вызова двух методов: первый выводит строку в консоль, а второй — в файл —

Live Demo

using System;
using System.IO;

namespace DelegateAppl {

   class PrintString {
      static FileStream fs;
      static StreamWriter sw;
      
      // delegate declaration
      public delegate void printString(string s);

      // this method prints to the console
      public static void WriteToScreen(string str) {
         Console.WriteLine("The String is: {0}", str);
      }
      
      //this method prints to a file
      public static void WriteToFile(string s) {
         fs = new FileStream("c:\\message.txt",
         FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      
      // this method takes the delegate as parameter and uses it to
      // call the methods as required
      public static void sendString(printString ps) {
         ps("Hello World");
      }
      
      static void Main(string[] args) {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —