Делегаты - это объектно-ориентированные указатели на функции, используемые для callback-вызовов в среде CLR фирмы Microsoft. Делегат можно связать со статической функцией или с нестатическим методом любого класса (единственное условие - совпадение сигнатуры метода с сигнатурой, указанной в описании делегата). Затем связанную с делегатом функцию или метод можно вызывать, используя стандартный синтаксис вызова функции в C++. Несколько делегатов можно связать в цепочку. Благодаря этому можно "одним махом" вызвать все связанные с ними callback-функции. Следующий пример демонстрирует применение делегатов в языке C#.
using System;
using System.IO;
namespace CSharpDelegates {
class App {
// Определяем делегат Callback,
// который принимает 1 параметр и ничего не возвращает.
public delegate void Callback(string str);
// Это метод класса App.
public void OutputToConsole(string str) {
Console.WriteLine(str);
}
// А это статический метод класса App.
public static void OutputToFile(string str) {
StreamWriter sw = new StreamWriter("output.txt", true);
sw.WriteLine(str);
sw.Close();
}
public static void Main(string[] args) {
App app = new App();
// Создаём делегат.
App.Callback callback = null;
if (callback != null) callback("1");
// Добавляем ссылку на OutputToFile.
// Вызываем её через делегата.
callback += new App.Callback(App.OutputToFile);
if (callback != null) callback("2");
// Добавляем ссылку на OutputToConsole.
// Вызывается вся цепочка:
// сначала OutputToFile, потом OutputToConsole.
callback += new App.Callback(app.OutputToConsole);
if (callback != null) callback("3");
// Убираем ссылку на OutputToFile.
// Вызывается только OutputToConsole.
callback -= new App.Callback(App.OutputToFile);
if (callback!= null) callback("4");
// Убираем оставшуюся ссылку на OutputToConsole.
callback -= new App.Callback(app.OutputToConsole);
if (callback != null) callback("5");
}
}
}
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.