что такое delegate в c

Делегаты (Руководство по программированию на C#)

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

Делегаты используются для передачи методов в качестве аргументов к другим методам. Обработчики событий — это ничто иное, как методы, вызываемые с помощью делегатов. При создании пользовательского метода класс (например, элемент управления Windows) может вызывать этот метод при появлении определенного события. В следующем примере показано объявление делегата:

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

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

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

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

Общие сведения о делегатах

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

В этом разделе

Спецификация языка C#

Дополнительные сведения см. в разделе Делегаты в Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Источник

Делегаты, события и лямбды

Делегаты

Определение делегатов

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

Рассмотрим примение этого делегата:

Здесь сначала мы определяем делегат:

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

Для использования делегата объявляется переменная этого делегата:

С помощью свойства DateTime.Now.Hour получаем текущий час. И в зависимости от времени в делегат передается адрес определенного метода. Обратите внимание, что методы эти имеют то же возвращаемое значение и тот же набор параметров (в данном случае отсутствие параметров), что и делегат.

Затем через делегат вызываем метод, на который ссылается данный делегат:

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

Посмотрим на примере другого делегата:

В данном случае делегат Operation возвращает значение типа int и имеет два параметра типа int. Поэтому этому делегату соответствует любой метод, который возвращает значение типа int и принимает два параметра типа int. В данном случае это методы Add и Multiply. То есть мы можем присвоить переменной делегата любой из этих методов и вызывать.

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

Присвоение ссылки на метод

Оба способа равноценны.

Соответствие методов делегату

Этому делегату соответствует, например, следующий метод:

А следующие методы НЕ соответствуют:

Здесь метод SomeMethod2 имеет другой возвращаемый тип, отличный от типа делегата. SomeMethod3 имеет другой набор параметров. Параметры SomeMethod4 и SomeMethod5 также отличаются от параметров делегата, поскольку имеют модификаторы ref и out.

Добавление методов в делегат

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

При удалении методов из делегата фактически будет создаватья новый делегат, который в списке вызова методов будет содержать на один метод меньше.

Объединение делегатов

Делегаты можно объединять в другие делегаты. Например:

В данном случае объект mes3 представляет объединение делегатов mes1 и mes2. Объединение делегатов значит, что в список вызова делегата mes3 попадут все методы из делегатов mes1 и mes2. И при вызове делегата mes3 все эти методы одновременно будут вызваны.

Вызов делегата

В примерах выше делегат вызывался как обычный метод. Если делегат принимал параметры, то при ее вызове для параметров передавались необходимые значения:

Другой способ вызова делегата представляет метод Invoke() :

Если делегат принимает параметры, то в метод Invoke передаются значения для этих параметров.

Следует учитывать, что если делегат пуст, то есть в его списке вызова нет ссылок ни на один из методов (то есть делегат равен Null), то при вызове такого делегата мы получим исключение, как, например, в следующем случае:

Поэтому при вызове делегата всегда лучше проверять, не равен ли он null. Либо можно использовать метод Invoke и оператор условного null:

Если делегат возвращает некоторое значение, то возвращается значение последнего метода из списка вызова (если в списке вызова несколько методов). Например:

Делегаты как параметры методов

Также делегаты могут быть параметрами методов:

Источник

System.Delegate и ключевое слово delegate

Определение типов делегатов

В качестве примера будем по-прежнему использовать метод List.Sort(). Первым шагом является создание типа для делегата сравнения.

Обратите внимание, что синтаксис может отображаться так, будто он объявляет переменную, но на самом деле он объявляет тип. Можно определить типы делегатов внутри классов, непосредственно внутри пространств имен или даже в глобальном пространстве имен.

Не рекомендуется объявлять типы делегатов (или другие типы) непосредственно в глобальном пространстве имен.

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

Объявление экземпляров делегатов

После определения делегата можно создать экземпляр этого типа. Как и все переменные в C#, экземпляры делегата нельзя объявлять непосредственно в пространстве имен или в глобальном пространстве имен.

В приведенном выше фрагменте кода была объявлена переменная-член в классе. Можно также объявить переменные делегатов, локальные переменные или аргументов для методов.

Вызов делегатов

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

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

Назначение, добавление и удаление целевых объектов вызова

Сведения о том, как определяется тип делегата и как объявляются и вызываются экземпляры делегата.

Предположим, требуется отсортировать список строк по их длине. Функция сравнения может выглядеть следующим образом:

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

Чтобы создать эту связь, передайте метод в метод List.Sort() :

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

Вы также явно объявили переменную типа Comparison и выполнили назначение:

Если в качестве объекта делегата используется небольшой метод, для назначения обычно применяется синтаксис лямбда-выражения:

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

В примере Sort() к делегату обычно подключается один целевой метод. Однако объекты делегатов поддерживают списки вызовов, где к объекту делегата присоединено несколько целевых методов.

Классы Delegate и MulticastDelegate

Класс System.Delegate и его прямой вложенный класс System.MulticastDelegate обеспечивают поддержку платформы для создания делегатов, регистрации методов в качестве целевых объектов делегатов и вызова всех методов, которые зарегистрированы как целевые объекты делегатов.

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

Несмотря на то, что невозможно создать производные классы напрямую, вы будете использовать методы, определенные в этих классах. Разберем наиболее распространенные методы, которые будут использоваться при работе с делегатами.

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

Источник

Общие сведения о делегатах

Например, рассмотрим сортировку списка звезд в астрономическом приложении. Можно отсортировать звезды по расстоянию от Земли, по величине или по воспринимаемой яркости.

Во всех этих случаях метод Sort() выполняет, по сути, одно и то же: упорядочивает элементы в списке на основе некоего сравнения. Для каждого порядка сортировки используется разный код, сравнивающий две звезды.

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

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

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

Цели разработки языка для делегатов

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

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

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

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

Источник

Практическое руководство. Определение и использование делегатов (C++/CLI)

В этой статье показано, как определить и использовать делегаты в C++/CLI.

Функция Main использует статический метод, определяемый SomeClass для создания экземпляра MyCallback делегата. Затем делегат станет альтернативным методом вызова этой функции, как показано путем отправки строки «Single» в объект делегата. Затем дополнительные экземпляры MyCallback связываются вместе, а затем выполняются одним вызовом к объекту делегата.

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

Создание делегатов

Выходные данные

Передать делегат ^ в собственную функцию, которая принимает указатель на функцию

Из управляемого компонента можно вызвать собственную функцию с параметрами указателя функции, где собственная функция затем может вызывать функцию-член делегата управляемого компонента.

Выходные данные

Связывание делегатов с неуправляемыми функциями

Выходные данные

Использование несвязанных делегатов

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

Несвязанные делегаты особенно полезны, если требуется выполнить итерацию по объектам в коллекции — с помощью for each, в ключевом слове — и вызвать функцию-член для каждого экземпляра.

Вот как объявить, создать экземпляр и вызвать привязку и несвязанные делегаты:

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

После первого параметра сигнатура делегата должна соответствовать сигнатуре функции, которую необходимо вызвать через делегат.

Создать экземплярПри создании экземпляра привязанного делегата можно указать функцию экземпляра или глобальную или статическую функцию-член.

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

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

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

В этом образце показано, как объявить, создать экземпляр и вызвать несвязанные делегаты:

Выходные данные

В следующем примере показано, как использовать несвязанные делегаты и ключевые слова For Each для перебора объектов в коллекции и вызова функции-члена для каждого экземпляра.

Этот пример создает непривязанный делегат для функций доступа к свойству:

Выходные данные

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

Выходные данные

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *