Понимание делегатов в C#: Руководство по ссылкам на методы и событиям
Что такое делегаты в C#
Делегаты в C# аналогичны указателям на функции в C или C++. Делегат — это ссылочный тип, который хранит ссылку на метод. Эта ссылка может быть изменена во время выполнения программы.
Делегаты особенно полезны для реализации событий и методов обратного вызова (callback). Все делегаты неявно наследуются от класса System.Delegate.
Объявление делегатов
Объявление делегата определяет сигнатуру методов, на которые он может ссылаться. Делегат может указывать на любой метод, имеющий такую же сигнатуру, как и сам делегат.
Например, рассмотрим следующий делегат:
public delegate int MyDelegate(string s);
Этот делегат может ссылаться на любой метод, принимающий один параметр типа string и возвращающий значение типа int.
Синтаксис объявления делегата:
delegate <тип_возврата> <имя_делегата> <список_параметров>
Создание экземпляров делегатов
После объявления типа делегата необходимо создать его экземпляр с помощью ключевого слова new и связать с конкретным методом. При создании делегата аргумент, передаваемый в выражение new, записывается как вызов метода, но без аргументов самого метода. Например:
public delegate void printString(string s); ... printString ps1 = new printString(WriteToScreen); printString ps2 = new printString(WriteToFile);
Ниже приведён полный пример, демонстрирующий объявление, создание и использование делегата, который ссылается на методы, принимающие целое число и возвращающие целое число.
Live Demousing 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) {
// Создание экземпляров делегата
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
// Вызов методов через объекты делегата
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
Мульти 播送 (Multicasting) делегатов
Объекты-делегаты можно объединять с помощью оператора +. Объединённый.delegate вызывает оба метода, из которых он состоит. Объединять можно только делегаты одного типа. Оператор - позволяет удалить компонентный делегат из объединённого.
Используя это свойство, можно создать список вызовов (invocation list) методов, которые будут вызваны при вызове делегата. Это называется мульти播送ом делегата. Следующая программа демонстрирует эту возможность:
Live Demousing 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) {
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// Вызов мульти播送-делегата
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
Результат выполнения:
Value of Num: 75
Практическое использование делегатов
В следующем примере показано использование делегата printString, который может ссылаться на метод, принимающий строку и ничего не возвращающий.
Мы используем этот делегат для вызова двух методов: первый выводит строку в консоль, второй — записывает её в файл.
Live Demousing System;
using System.IO;
namespace DelegateAppl {
class PrintString {
static FileStream fs;
static StreamWriter sw;
// объявление делегата
public delegate void printString(string s);
// метод вывода в консоль
public static void WriteToScreen(string str) {
Console.WriteLine("The String is: {0}", str);
}
// метод записи в файл
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();
}
// метод, принимающий делегат как параметр
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();
}
}
}
Результат выполнения:
The String is: Hello World
Язык C
- C# Hello World — создание вашего первого C# приложения
- Понимание ключевых слов и идентификаторов C#: правила, списки и лучшие практики
- Мастерство C# переменных и примитивных типов данных: полное руководство
- Операторы C# — исчерпывающее руководство по операторам в C#
- Четыре проверенных паттерна пользовательских функций в C
- Как передавать одномерные и двумерные массивы в функции в C — практическое руководство
- ИИ в центре внимания на Economist Innovation Summit: лидеры призывают усиливать, а не заменять человеческие навыки
- Переменные и типы данных в C++: подробное руководство по int, double, char, string, bool
- Функции в C: объявление, определение, вызов, аргументы (по значению и по ссылке), рекурсия
- Битовые поля в C: компактное хранение флагов и малых целых чисел