Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Делегат — это тип, который безопасно инкапсулирует метод, аналогичный указателю функции в C и C++. В отличие от указателей функций C, делегаты являются объектно-ориентированными, типобезопасны и безопасны. В следующем примере объявляется делегат с именем Callback , который может инкапсулировать метод, который принимает строку в качестве аргумента и возвращает void:
public delegate void Callback(string message);
Объект делегата обычно создается путем указания имени метода, который делегат оборачивает, или с использованием лямбда-выражения. Делегат можно вызвать, как только он будет создан. Вызов делегата вызывает метод, подключенный к экземпляру делегата. Параметры, передаваемые делегату вызывающим кодом, передаются методу. Делегат возвращает возвращаемое значение, если таковое имеется, из метода. Рассмотрим пример.
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;
// Call the delegate.
handler("Hello World");
Типы делегатов являются производными от Delegate класса в .NET. Типы делегатов запечатанные, они не могут быть производными от, и невозможно наследовать пользовательские классы от Delegate. Так как экземпляр делегата является объектом, его можно передать в качестве аргумента или присвоить свойству. Метод может принять делегат в качестве параметра и вызвать его в более позднее время. Это называется асинхронным обратным вызовом и является общим методом уведомления вызывающего объекта при завершении длительного процесса. Если делегат используется таким образом, код, использующий делегат, не нуждается в знании о реализации используемого метода. Функциональность аналогична той, которую обеспечивают интерфейсы инкапсуляции.
Другое частое использование обратных вызовов — определение пользовательского метода сравнения и передача делегата в метод сортировки. Он позволяет вызывающему коду стать частью алгоритма сортировки. В следующем примере метода в качестве параметра используется Callback тип:
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
Затем делегат, созданный в предыдущем примере, можно передать в этот метод:
MethodWithCallback(1, 2, handler);
И получите следующие выходные данные в консоли:
The number is: 3
MethodWithCallback не требуется вызывать консоль напрямую— ее не нужно разрабатывать с учетом консоли. Что делает MethodWithCallback — это подготавливает строку и передаёт её другому методу. Делегированный метод может использовать любое количество параметров.
При создании делегата для оболочки метода экземпляра, делегат ссылается как на сам экземпляр, так и на метод. Делегат не имеет знаний о типе экземпляра, кроме метода, который он упаковывает. Делегат может ссылаться на любой тип объекта, если в этом объекте есть метод, соответствующий сигнатуре делегата. Когда делегат создается для упаковки статического метода, он ссылается только на метод. Рассмотрим следующие объявления:
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}
Наряду со статическим DelegateMethod, показанным ранее, теперь у нас есть три метода, которые можно обернуть в экземпляр Callback.
Делегат может вызывать более одного метода при активации, что называется мультикастингом. Чтобы добавить дополнительный метод в список методов делегата — список вызовов, просто требуется добавить два делегата с помощью операторов добавления или добавления ("+" или "+="). Рассмотрим пример.
var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;
//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
allMethodsDelegate содержит три метода в списке вызовов: Method1, Method2, и DelegateMethod. Исходные три делегата, d1d2, и d3, остаются неизменными. При вызове allMethodsDelegate все три метода вызываются в упорядоченном виде. Если делегат использует ссылочные параметры, ссылка передается последовательно каждому из трех методов, и любые изменения по одному методу видны следующему методу. Если любой метод выбрасывает исключение, которое не поймано в методе, это исключение передается вызывающей стороне делегата. В списке вызовов не вызываются последующие методы. Если делегат имеет возвращаемое значение и/или параметры выхода, возвращает возвращаемое значение и параметры последнего вызываемого метода. Чтобы удалить метод из списка вызовов, используйте операторы вычитания или присваивания вычитания (- или -=). Рассмотрим пример.
//remove Method1
allMethodsDelegate -= d1;
// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;
Так как типы делегатов являются производными от System.Delegate, методы и свойства, определенные тем классом, можно вызвать на делегате. Например, чтобы найти количество методов в списке вызовов делегата, можно написать следующее:
int invocationCount = d1.GetInvocationList().GetLength(0);
Делегаты с несколькими методами в списке вызовов происходят от MulticastDelegate, который является суперклассом System.Delegate. Предыдущий код работает в любом случае, так как оба класса поддерживают GetInvocationList.
Делегаты многоадресной рассылки широко используются в обработке событий. Объекты источника событий отправляют уведомления о событиях получателям, зарегистрированным для получения этого события. Чтобы зарегистрировать событие, получатель создает метод, предназначенный для обработки события, а затем создает делегат для этого метода и передает этот делегат источнику данного события. Источник вызывает делегата при возникновении события. Затем делегат вызывает метод обработки событий у получателя, передавая данные события. Источник событий определяет тип делегата для данного события. Дополнительные сведения см. в разделе "События".
Сравнение делегатов двух разных типов, назначенных во время компиляции, приводит к ошибке компиляции. Если экземпляры делегата статически относятся к типу System.Delegate, то сравнение допускается, но возвращает значение false во время выполнения. Рассмотрим пример.
delegate void Callback1();
delegate void Callback2();
static void method(Callback1 d, Callback2 e, System.Delegate f)
{
// Compile-time error.
Console.WriteLine(d == e);
// OK at compile-time. False if the run-time type of f
// is not the same as that of d.
Console.WriteLine(d == f);
}