Введение
Делегаты — одна из самых важных функций C#. Они позволяют создавать ссылки на методы и передавать их в качестве аргументов другим методам. Делегаты часто используются в обработке событий, функциях обратного вызова и асинхронном программировании. В этой статье мы рассмотрим, что такое делегаты, как они работают и как их можно использовать в коде C#.

Делегату может быть назначен любой метод из любого доступного класса или структуры, соответствующий типу делегата. Метод может быть либо статическим, либо методом экземпляра. Эта гибкость означает, что вы можете программно изменять вызовы методов или вставлять новый код в существующие классы.

В контексте перегрузки метода сигнатура метода не включает возвращаемое значение. Но в контексте делегатов подпись включает возвращаемое значение. Другими словами, метод должен иметь тот же тип возвращаемого значения, что и делегат.

Делегаты идеально подходят для указания методов обратного вызова, поскольку их можно использовать в качестве параметров. В своем приложении вы можете создать метод, сравнивающий два элемента. Делегат для алгоритма сортировки может использовать этот подход. Функция сортировки может быть более широкой, поскольку код сравнения отделен от библиотеки.

Для сопоставимых обстоятельств, когда вам нужен дополнительный контроль над соглашением о вызовах, в C# 9 были добавлены указатели функций. Виртуальный метод, добавленный к типу делегата, используется для выполнения кода, связанного с делегатом. Несколько соглашений могут быть указаны с помощью указателей на функции.

В .NET типы делегирования происходят от класса Delegate. Невозможно создать пользовательские классы из делегата, потому что это запечатанный тип, от которого нельзя наследовать. Созданный экземпляр делегата может быть предоставлен в качестве аргумента или назначен свойству, поскольку он является объектом. В результате метод может принять делегат в качестве параметра, а затем вызвать делегата.

Асинхронный обратный вызов — популярный метод информирования вызывающей стороны о завершении длительной процедуры. Когда делегат используется таким образом, код, использующий делегат, не требуется для понимания того, как реализуется используемый метод. Аналогичная функциональность предлагается интерфейсами инкапсуляции.

Что такое съезд делегатов?

Делегат — это тип, представляющий ссылку на метод с определенной сигнатурой. Сигнатура метода представляет собой комбинацию его имени и параметров. Делегат позволяет хранить ссылку на метод и вызывать его позже.

Тип делегата определяется с помощью ключевого слова delegate, за которым следует тип возвращаемого значения и типы параметров метода, на который он будет ссылаться. Вот пример типа делегата:

delegate void MyDelegate(int x, int y);

Этот тип делегата можно использовать для ссылки на любой метод, который принимает два целочисленных параметра и возвращает значение void.

Обзор делегатов

Делегаты обладают следующими свойствами:

  • Делегаты похожи на указатели функций C++, но делегаты полностью объектно-ориентированы, и в отличие от указателей C++ на функции-члены, делегаты инкапсулируют как экземпляр объекта, так и метод.
  • Делегаты позволяют передавать методы в качестве параметров.
  • Делегаты могут использоваться для определения методов обратного вызова.
  • Делегаты могут быть связаны вместе; например, для одного события можно вызвать несколько методов.
  • Методы не обязательно должны точно соответствовать типу делегата.
  • Лямбда-выражения — это более краткий способ написания встроенных блоков кода. Лямбда-выражения (в определенных контекстах) компилируются в типы делегатов.

Как объявлять и использовать делегатов

Чтобы объявить переменную делегата, вам сначала нужно создать экземпляр делегата, используя ключевое слово new и предоставив метод, на который вы хотите сослаться, в качестве аргумента. Вот пример:

MyDelegate del = new MyDelegate(MyMethod);

Это создает новый экземпляр делегата MyDelegate и устанавливает для него ссылку на метод MyMethod.

Чтобы вызвать указанный метод, вы просто вызываете делегат с помощью оператора ():

del(2, 3);

Это вызовет метод MyMethod с аргументами 2 и 3.

Делегаты также могут использоваться в качестве параметров для других методов. Например, вот метод, который принимает делегат в качестве параметра:

void DoSomething(MyDelegate del) {
    del(2, 3);
}

Вы можете вызвать этот метод и передать переменную делегата следующим образом:

DoSomething(del);

Это вызовет метод DoSomething и передаст переменную делегата MyDelegate, которая затем вызовет указанный метод MyMethod с аргументами 2 и 3.

Делегаты многоадресной рассылки

Многоадресный делегат — это делегат, который ссылается на несколько методов. Вы можете использовать операторы + и - для добавления и удаления методов из многоадресного делегата. Когда вы вызываете многоадресный делегат, все методы, на которые он ссылается, вызываются в том порядке, в котором они были добавлены.

Вот пример создания и вызова многоадресного делегата:

MyDelegate del1 = new MyDelegate(MyMethod1);
MyDelegate del2 = new MyDelegate(MyMethod2);
MyDelegate del3 = del1 + del2;

del3(2, 3);

Это создает два экземпляра делегата, ссылающихся на два разных метода, а затем объединяет их в один многоадресный делегат, del3. Когда вызывается del3, MyMethod1 и MyMethod2 вызываются в том порядке, в котором они были добавлены.

Еще одно распространенное использование обратных вызовов — определение пользовательского метода сравнения и передача этого делегата методу сортировки. Это позволяет коду вызывающего объекта стать частью алгоритма сортировки. В следующем примере метода в качестве параметра используется тип Del:

public static void MethodWithCallback(int param1, int param2, Del 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) { }
}

При обработке событий часто используются многоадресные делегаты. объекты-приемники, зарегистрированные для получения этого события, получают предупреждения о событиях от объектов-источников событий. Получатель создает метод для обработки события, затем создает делегата для этого метода и передает делегата источнику события для регистрации на событие. Когда событие происходит, источник вызывает делегата. Затем делегат вызывает метод обработки события получателя, отправляя данные события. Источник события для определенного события устанавливает тип делегата.

Заключение

Одним из ключевых компонентов C# является делегирование. Они позволяют создавать ссылки на методы, которые можно передавать в качестве аргументов другим методам. Управление событиями, процедуры обратного вызова и асинхронное программирование часто используют делегаты.

Об авторе:

Как вы знаете, меня зовут Сайфулла Хакро. Я получил степень бакалавра компьютерных наук в FAST NUCES Karachi в период с 2013 по 2017 год со средним баллом 3,49. Я работаю разработчиком программного обеспечения в секторе программного обеспечения с 2017 года, уделяя особое внимание домену .NET. Мне нравится создавать статьи и читать книги.

Отказ от ответственности:

Эти идеи исходят из моего опыта и исследований, поэтому они могут быть не совсем точными или безупречными.