Делегат (CLI)
Делегат — это форма типобезопасного указателя функции, используемая Common Language Infrastructure (CLI). Делегаты указывают метод для вызова и, при необходимости, объект для вызова этого метода. Делегаты используются, помимо прочего, для реализации обратных вызовов и прослушивателей событий . Объект делегата инкапсулирует ссылку на метод. Затем объект делегата можно передать в код, который может вызвать указанный метод, без необходимости знать во время компиляции, какой метод будет вызван.
Делегат многоадресной рассылки — это делегат, указывающий на несколько методов. [1] [2] Многоадресное делегирование — это механизм, обеспечивающий возможность выполнения более чем одного метода. Существует список делегатов, поддерживаемый внутри, и когда вызывается делегат многоадресной рассылки, список делегатов выполняется.
В C# делегаты часто используются для реализации обратных вызовов в программировании, управляемом событиями. Например, делегат может использоваться для указания того, какой метод следует вызывать, когда пользователь нажимает какую-либо кнопку. Делегаты позволяют программисту уведомить несколько методов о произошедшем событии. [3]
Пример кода С#
[ редактировать ]Код для объявления delegate тип, названный SendMessageDelegate, что занимает Message в качестве параметра и возвращает void:
delegate void SendMessageDelegate(Message message);
Код для определения метода, который принимает экземпляр делегата в качестве аргумента:
void SendMessage(SendMessageDelegate sendMessageDelegateReference)
{
// Call the delegate and any other chained delegates synchronously.
sendMessageDelegateReference(new Message("hello this is a sample message"));
}
Реализованный метод, который запускается при вызове делегата:
void HandleSendMessage(Message message)
{
// The implementation for the Sender and Message classes are not relevant to this example.
Sender.Send(message);
}
Код для вызова метода SendMessage с передачей экземпляра делегата в качестве аргумента:
SendMessage(new SendMessageDelegate(HandleSendMessage));
Делегаты (C#)
[ редактировать ]delegate void Notifier(string sender); // Normal method signature with the keyword delegate
Notifier greetMe; // Delegate variable
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
greetMe = new Notifier(HowAreYou);
Переменная-делегат вызывает связанный метод и вызывается следующим образом:
greetMe("Anton"); // Calls HowAreYou("Anton") and prints "How are you, Anton?"
Делегатные переменные — это первоклассные объекты вида new DelegateType(obj.Method)
и может быть присвоен любому методу сопоставления или значению null
. Они хранят метод и его получатель без каких-либо параметров: [4]
new DelegateType(funnyObj.HowAreYou);
Объект funnyObj
может быть this
и опущено. Если метод static
, это должен быть не объект (также называемый экземпляром в других языках), а сам класс. Это не должно быть abstract
, но может быть new
, override
или virtual
.
Для успешного вызова метода с делегатом сигнатура метода должна соответствовать DelegateType
с одинаковым количеством однотипных параметров ( ref
, out
, value
) того же типа (включая тип возвращаемого значения).
Делегаты многоадресной рассылки (C#)
[ редактировать ]Переменная-делегат может содержать несколько значений одновременно:
void HowAreYou(string sender)
{
Console.WriteLine($"How are you, {sender}?");
}
void HowAreYouToday(string sender)
{
Console.WriteLine($"How are you today, {sender}?");
}
Notifier greetMe;
greetMe = HowAreYou;
greetMe += HowAreYouToday;
greetMe("Leonardo"); // "How are you, Leonardo?"
// "How are you today, Leonardo?"
greetMe -= HowAreYou;
greetMe("Pereira"); // "How are you today, Pereira?"
Если делегат многоадресной рассылки является функцией или не имеет out
параметр, возвращается параметр последнего вызова. [5]
Детали технической реализации
[ редактировать ]внутренние реализации могут различаться, экземпляры делегата можно рассматривать как кортеж объекта Хотя , метода указателя и ссылки (возможно, нулевой) на другой делегат. Следовательно, ссылка на одного делегата может быть ссылкой на несколько делегатов. Если после завершения работы первого делегата ссылка на его цепочку не равна нулю, будет вызван следующий и так далее, пока список не будет завершен. Этот шаблон позволяет событие легко масштабировать от одной ссылки до отправки в список делегатов и широко используется в CLI.
Производительность
[ редактировать ]Раньше производительность делегатов была намного медленнее, чем вызов виртуального или интерфейсного метода (в 6–8 раз медленнее в тестах Microsoft 2003 года). [6] но, начиная с .NET 2.0 CLR в 2005 году, это примерно то же самое, что и вызовы интерфейса. [7] Это означает, что существуют небольшие дополнительные накладные расходы по сравнению с прямым вызовом методов.
Существуют очень строгие правила построения классов делегатов. Эти правила предоставляют оптимизирующим компиляторам большую свободу действий при оптимизации делегатов, обеспечивая при этом безопасность типов. [ нужна ссылка ]
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Статья Microsoft Developer Network (MSDN) , Как объединить делегатов (многоадресные делегаты) (Руководство по программированию на C#) , по состоянию на 20 мая 2008 г.
- ^ «О «Делегатах» Microsoft » . Сеть разработчиков Sun. Сан Микросистемс. Архивировано из оригинала 10 февраля 1999 года.
- ^ Wikibooks: Программирование C Sharp / Делегаты и события
- ^ Мессенбёк, Ханспетер (25 марта 2002 г.). «Расширенный C#: переменное количество параметров» (PDF) . Институт системного программного обеспечения, Университет Иоганна Кеплера в Линце, факультет компьютерных наук. стр. 23–24 . Проверено 4 августа 2011 г.
- ^ Мессенбёк, Ханспетер (25 марта 2002 г.). «Расширенный C#: переменное количество параметров» . Институт системного программного обеспечения, Университет Иоганна Кеплера в Линце, факультет компьютерных наук. п. 25 . Проверено 4 августа 2011 г.
- ^ Грей, Ян (июнь 2003 г.). «Написание более быстрого управляемого кода: знайте, чего это стоит» . Майкрософт . Проверено 9 сентября 2007 г.
- ^ Штурм, Оливер (1 сентября 2005 г.). «В .NET 2 вызовы делегатов значительно ускорились» . Проверено 9 сентября 2007 г.