Как делегаты, действия и функции работают в C#?
Делегаты, действия и функции — все типы C#, ориентированные на схожую концепцию: хранение ссылок в переменной на функции и методы, которые можно вызывать позже для выполнения метода, на который они указывают. Мы обсудим различия между различными типами и способы их использования.
Что такое делегаты?
Делегаты — это, по сути, безопасные с точки зрения типов указатели на функции. Делегат — это просто переменная, которая указывает на метод и «делегирует» ему выполнение. Метод, на который он указывает, может быть именованным, как метод члена класса, или анонимным, как в случае со стрелочными функциями.
Делегаты состоят из двух основных частей: определения типа и реализации. Определение типа обеспечивает безопасность типов, поэтому, если вы хотите принимать только метод, который принимает строку
и возвращает логическое значение, вам нужно определить его как обычную функцию, за исключением делегировать
параметр и нет фактического кода.
Затем вы можете написать реализацию или несколько реализаций, которые имеют одни и те же возвращаемые и входные параметры, но на самом деле содержат в себе код.
Затем вы можете использовать определение делегата как параметр типа, создав новую переменную, указывающую на реальную функцию. Когда вы хотите вызвать делегата, вы можете вызвать его как метод и передать ему правильные параметры. Среда выполнения .NET проверит, на какой метод указывает делегат, и вызовет этот метод.
Уже довольно ясно, где это весьма полезно — если у вас есть несколько функций, которые принимают одни и те же входные параметры, но должны вызывать разные версии в зависимости, например, от входного перечисления, вы можете назначить каждому значению перечисления делегат и использовать его. вместо того, чтобы дублировать логику в большом операторе switch.
Однако делегаты не должны указывать на именованные методы, поскольку они гораздо полезнее, когда указывают на анонимные функции. Они создаются с использованием синтаксиса стрелочных функций, () => {}
, который определяет функцию без имени, следовательно, «анонимную». Вы можете использовать их так же, как обычные делегаты.
Действия и функции — это просто делегаты с определенными аргументами и возвращаемыми параметрами. Действия могут принимать любое количество аргументов, но возвращать void
. Funcs может принимать любое количество аргументов, но всегда возвращает значение, определяемое последним параметром типа.
На самом деле это всего лишь готовые определения делегатов с общим типом T
. Action
без каких-либо типов – это просто пустое определение делегата с типом возвращаемого значения void
.
Вы, вероятно, много использовали Funcs, не задумываясь об этом. Это функции, которые вы передаете перечисляемым запросам, таким как .Where()
, для выбора элементов. Эти виды функций, в частности, называются предикатами, а Predicate
функционально эквивалентно написанию Func
. Однако на самом деле они не особенные, кроме определенного имени.
На самом деле вы можете строго определить Func
, присвоить ему функцию в качестве значения и передать его в .Where()
, что выглядит странно тревожным, учитывая вас. обычно делают это встроенным без определения типа или переменной, но это вполне допустимо:
Вы можете строго определить Predicate
вместо Func
У делегатов есть несколько других интересных свойств. Поскольку это просто переменные, вы можете хранить их в списках и словарях, как и любой другой тип ссылки. Вы можете перебирать все делегаты в списке и вызывать каждого из них по очереди.
Вы также можете многоадресная рассылка делегатов, что означает, что вы можете добавлять их вместе. Например, в следующем примере определяется делегат Greeting, который принимает имя и приветствует пользователя. Определены две реализации: Hello
– приветствие и Goodbye
– прощание.
Затем вы можете буквально просто добавить их вместе с оператором со знаком плюс, хотя обратите внимание, что здесь ожидается делегат, а не группа методов, поэтому вам нужно обернуть имя функции в new DelegateDefinition()
чтобы он работал правильно. Этот комбинированный делегат выполняет оба элемента в том порядке, в котором они были добавлены.
Вы можете вычесть делегаты, что удалит их из списка, хотя операторов умножения почему-то нет, и деление здесь не имеет никакого смысла.