Делегаты
Ключевое слово _delegate (делегат) используется для объявления класса-делегата, основанного на описании сигнатуры метода. Делегаты очень сходны с указателями на функции в обычном C++, с той лишь разницей, что делегат может указывать только на метод управляемого класса. Чаще всего в приложениях .NET Framework делегаты используются для реализации функций обратного вызова или обработки событий. Однако они могут найти применение во всех случаях, когда необходимо вызывать методы динамически.
В .NET Framework определены (как абстрактные классы) два типа делегатов – System::Delegate (Система::Делегат) и System::MulticastDelegate. Эти два типа делегатов используются как базовые классы для одноадресных (или делегатов единственного приведения – single-cast) и многоадресных (или групповых – multicast) делегатов соответственно. Одноадресный делегат связывает указатель на метод с методом одного управляемого объекта, тогда как многоадресный делегат связывает указатель на метод с одним или несколькими методами управляемого объекта. Вызов одноадресного делегата приводит к вызову только одного метода, а при вызове многоадресного делегата может выполняться неограниченное количество методов. В связи с тем, что многоадресный делегат можно использовать и для вызова одного метода, одноадресная форма делегата является излишней. Обычно в программах используются лишь многоадресные делегаты.
Встретив в программе ключевое слово _delegate (делегат) компилятор создает особый управляемый класс, производный от System::MulticastDelegate. Конструктор этого класса имеет два аргумента: указатель на экземпляр управляемого класса (который равен нулю, если делегат связывает статический метод), и сам метод, вызываемый с помощью делегата. Этот класс также содержит метод Invoke (Запустить), сигнатура которого совпадает с сигнатурой метода, вызываемого делегатом. Следующий пример демонстрирует использование делегатов:
//DelegateExample.срр #using <mscorlib.dll> using namespace System; // использовать пространство имен Система; // определить управляемые классы для использования // в качестве делегатов _delegate int SomeDelegate // делегат (int i, int j); _delegate // делегат void SomeOtherDelegate (int i); _gc class SomeClass // класс сборщика мусора SomeClass содержит методы, // вызываемые делегатами { public: int SomeMethod(int i, int j) { Console::WriteLine( "SomeMethod({0}, {!})", _box(i), _box(j)); return i+j; } static int SomeStaticMethod(int i, int j) // статический { Console::WriteLine( "SomeStaticMethod({0}, {!})", _box(i), _box(j)); return i+j; } void SomeOtherMethod(int i) { Console::WriteLine( 11 SomeOtherMethod ({0}) ", _box(i)); } }; Void main () { SomeDelegate *pscd; int sum; // сумма // связать делегат с нестатическим методом // требуется экземпляр SomeClass SomeClass * psc = newSomeClass(); pscd = // создать экземпляр класса делегат sc new SomeDelegate( psc, SSomeClass::SomeMethod); // нестатический sum = pscd › Invoke(3, 4); // вызвать метод через делегат // сумма = pscd › вызвать (3, 4); Console::WriteLine(sum); // сумма // связать делегат со статическим методом, – нет нужды // ни в каком экземпляре pscd = // создать другой экземпляр класса делегата sc new SomeDelegate((), SSomeClass::SomeStaticMethod); // статический sum = pscd › Invoke(3, 4); // вызвать метод через делегата // сумма = pscd › вызвать (3, 4); Console::WriteLine(sum); // сумма // объединить два делегата SomeClass * pscl = new SomeClass(); SomeClass * psc2 = new SomeClass(); SomeOtherDelegate *pmcdl = new SomeOtherDelegate( psc1, &SomeClass::SomeOtherMethod); SomeOtherDelegate *pmcd2 = new SomeOtherDelegate( psc2, SSomeClass::SomeOtherMethod); SomeOtherDelegate *pmcd = static_cast<SomeOtherDelegate *>(Delegate:.Combine( // Объединение делегатов pmcdl, pmcd2)); pmcd › Invoke(1); // Вызвать } SomeMethod(3, 4) 7 SomeStaticMethod(3, 4) 7 SomeOtherMethod(I) SomeOtherMethod(1)