Книга: C# для профессионалов. Том II
Делегаты
Делегаты
Делегаты в C# не имеют прямого эквивалента в C++ и выполняют ту же самую задачу, что и указатели на функции в C++. Идея делегата состоит в том, что указатель на метод помещается в специальный класс вместе со ссылкой на объект, на котором вызывается метод (для метода экземпляра или со ссылкой null
для статического метода). Это означает, что в отличие от указателя на функцию в C++, делегат C# содержит достаточно информации для вызова метода экземпляра.
Формально делегат является классом, который выводится из класса System.Delegate
. Следовательно, создание экземпляра делегата включает два этапа: определение этого производного класса и объявление переменной соответствующего типа. Определение класса делегата включает данные полной сигнатуры (с возвращаемым типом) метода, который содержит делегат.
Основное использование делегатов состоит в передаче и вызове ссылок на методы: ссылки на методы нельзя передавать непосредственно, но они могут передаваться внутри делегата. Делегат обеспечивает безопасность типа данных, не позволяя вызывать метод с неверной сигнатурой. Метод, который содержит делегат, может вызываться синтаксически как вызов делегата. Следующий код показывает общие принципы. Первое, необходимо определить класс делегата:
// определить класс делегата, который представляет метод,
// получающий int и возвращающий void
delegate void MyOp(int X);
Затем, для целей этого примера объявим класс, который содержит вызываемый метод:
// затем определение класса
class MyClass {
void MyMethod(int X) {
// и т.д.
}
}
Еще позже, может быть при реализации некоторого другого класса, имеется метод, которому должна быть передана ссылка на метод с помощью делегата:
void MethodThatTakesDelegate(MyOp Op) {
// вызвать метод, передавая ему значение 4
Oр(4);
}
// и т.д.
И, наконец, код, который реально использует делегата:
MyClass Mine = new MyClass();
// Создать экземпляр делегата MyOp. Настроить его,
// чтобы он указывал на метод MyMethod из Mine.
MyOp DoIt = new MyOp(Mine.MyMethod);
После объявления переменной делегата можно вызвать метод с помощью делегата:
DoIt();
Или передать его в другой метод:
MethodThatTakesDelegate(DoIt);
В частном случае, когда делегат представляет метод, который возвращает void
, этот делегат является широковещательным делегатом и может одновременно представлять более одного метода. Вызов делегата заставляет все методы вызываться по очереди. Можно использовать операторы +
и +=
для добавления метода делегату, а -
и -=
— для удаления метода, который уже находится в делегате. Делегаты рассматриваются более подробно в главе 6.