A делегат - это форма type-sa fe указатель на функцию, используемый Common Language Infrastructure (CLI). Делегаты указывают метод для вызова и, необязательно, объект для вызова метода. Среди прочего, делегаты используются для реализации обратных вызовов и прослушивателей событий. Объект делегата инкапсулирует ссылку на метод. Затем объект делегата может быть передан в код, который может вызывать метод, на который указывает ссылка, без необходимости знать во время компиляции, какой метод будет вызван.
A делегат многоадресной рассылки - это делегат, указывающий на несколько методов. Делегирование многоадресной рассылки - это механизм, который обеспечивает функциональность для выполнения более чем одного метода. Существует список делегатов, поддерживаемый внутри, и когда вызывается делегат многоадресной рассылки, список делегатов выполняется.
В C # делегаты часто используются для реализации обратных вызовов в программировании, управляемом событиями. Например, делегат может использоваться, чтобы указать, какой метод должен быть вызван, когда пользователь нажимает какую-либо кнопку. Делегаты позволяют программисту уведомлять несколько методов о том, что произошло событие.
Код для объявления типа делегатас именем SendMessageDelegate, который принимает сообщение Messageв качестве параметра и возвращает void:
delegate void SendMessageDelegate (сообщение сообщения);
Код для определения метода, который принимает созданный экземпляр делегата в качестве аргумента:
void SendMessage (SendMessageDelegate sendMessageDelegateReference) {// Вызов делегата и любых других связанных делегатов синхронно. sendMessageDelegateReference (новое сообщение («привет, это образец сообщения»)); }
Реализованный метод, который запускается при вызове делегата:
void HandleSendMessage (Message message) {// Реализация для классов Sender и Message не имеет отношения к этому примеру. Sender.Send (сообщение); }
Код для вызова метода SendMessage с передачей созданного экземпляра делегата в качестве аргумента:
SendMessage (новый SendMessageDelegate (HandleSendMessage));
делегат void Notifier (отправитель строки); // Обычная подпись метода с ключевым словом delegate Notifier greetMe; // Делегируемая переменная void HowAreYou (отправитель строки) {Console.WriteLine ("Как дела," + отправитель + '?'); } greetMe = новый уведомитель (HowAreYou);
Переменная делегата вызывает связанный метод и вызывается следующим образом:
greetMe ("Антон"); // Вызывает HowAreYou ("Антон") и выводит "Как дела, Антон?"
Переменные-делегаты - это объекты первого класса формы new DelegateType (obj.Method)
, которые могут быть присвоены любому методу сопоставления или значению null
. Они хранят метод и его получатель без каких-либо параметров:
new DelegateType (funnyObj.HowAreYou);
Объект funnyObj
может быть этим
и опускаться. Если метод static
, это должен быть не объект (также называемый экземпляром в других языках), а сам класс. Это не должно быть abstract
, но может быть new
, override
или virtual
.
Для успешного вызова метода с делегатом подпись метода должен соответствовать DelegateType
с таким же количеством параметров одного типа (ref
, out
, value
) с тем же типом (включая возвращаемый тип).
Переменная делегата может одновременно содержать несколько значений:
void HowAreYou (отправитель строки) {Console.WriteLine ("How are you," + отправитель + '?'); } void HowAreYouToday (отправитель строки) {Console.WriteLine ("Как дела сегодня" + отправитель + '?'); } Уведомитель greetMe; greetMe = HowAreYou; greetMe + = HowAreYouToday; greetMe ("Леонардо"); // "Как дела, Леонардо?" // "Как дела, Леонардо?" greetMe - = HowAreYou; greetMe ("Перейра"); // "Как дела, Перейра?"
Если делегат многоадресной рассылки является функцией или не имеет параметра out
, возвращается параметр последнего вызова.
Хотя внутренний реализации могут отличаться, экземпляры делегата можно рассматривать как кортеж объекта и метод указатель и ссылка (возможно, пустая) на другой делегат. Следовательно, ссылка на одного делегата может быть ссылкой на несколько делегатов. Когда первый делегат завершит работу, если его ссылка на цепочку не равна нулю, будет вызываться следующий и так далее, пока список не будет завершен. Этот шаблон позволяет событию легко масштабировать накладные расходы от одиночной ссылки до отправки списку делегатов и широко используется в CLI.
Производительность делегатов раньше была намного ниже, чем при вызове метода виртуального или интерфейса (в 6-8 раз медленнее в тестах Microsoft 2003), но, начиная с .NET 2.0 CLR в 2005 году, это примерно то же самое, что и вызовы интерфейса. Это означает, что существуют небольшие дополнительные накладные расходы по сравнению с прямым вызовом методов.
Существуют очень строгие правила построения классов делегатов. Эти правила предоставляют оптимизирующим компиляторам большую свободу действий при оптимизации делегатов, обеспечивая при этом безопасность типов.