C#
Делегат - это способ передачи кода между разными частями программы. Лямбда функции призваны выполнять аналогичные функции 😉.
lambda expression is a preferred way to write inline code
Тип делегата - тип ссылки на метод, сигнатура метода. Подобно function pointers в C++. Ссылка на метод - это всегда хорошо :), ее можно передать куда-нибудь, например как функцию обратного вызова.
Делега т не может хранить ссылку на любую функцию так как при его определении нужно предоставить сигнатуру функции которая ограничит подмножество функций (есть способ расширить это подмножество, см. ниже).
Определение типа и создание переменной
Создание делегата начинается с определение типа который является сигнатурой метода.
public delegate double MathOp(double x, double y);
// лубая функция имеющая сигнатуру: double (double x, double y)
в этом примере мы опретеляем тип который нашего делегат, он типизирован сигнатурой и может быть использован для создания переменных.
Тепер мы можем создать переменную
// внешняя функция Add
public double Add(double x, double y) => x + y
// Переменная, хранящая ссылку на метод
public MathOp externalOp = Add;
// Вот так мы можем использовать наш делегат и вызвать внешнюю функция,
// ссылка на которую была присвоена переменной externalOp имеющий тип телегата MathOp
var result = externalOp(2, 2);
Мультикаст делегаты
Делегат может хранить более одной ссылки. Добавить или удалить ссылку в контейнер можно с использованием "+=" или "-=".
invocation list - список ссылок на функции которые будут вызваны при активации.
Например так
public double Add(double x, double y) => x + y
public double Sub(double x, double y) => x - y
public MathOp externalOp = Add;
externalOp += Sub
var result = externalOp(1, 1);
Для корректной работы мультикаст делегаты не должны возвращать значение. Если в сигнатуре определено возвращаемое значение, как в примере выше, то тогда результатом выполнения бедет результат работы последнего метода.
Исключение, возникшее при вызове мультикаст делегата прерывает обработку invocation list и методы следующие за упавшим не будут вызваны.
Распространенный метод борьбы с этим - использование Delegate.GetInvocationList
и ручная активация делегатов.
Мультикаст делегаты будут вызываться последоватьельно в порядке добавления.
Обобщенный/Generic делегат
Ослабить ограничения типизации. Ну или расширить подмножество функций ссылки на которые может хранить делегат можно, как и в случае обячных функций, с помощью обобщений
Например
delegate T MathOp<T> (T x, T y);
// valid
int Add(int x, int y) => x + y;
MathOp<int> mathOp = Add;
int result = mathOp(2, 2);
// or, also valid
double Add(double x, double y) => x + y;
MathOp<double> mathOp = Add;
double result = mathOp(0.2, 0.2);
в этом примере мы опретеляем тип делегата которые параметризирован типом переменных.
Анонимные делегаты или оператор delegate
В C# есть возможность создавать анонимные делегаты, которые не требуют именованой переменной и могут быть сразу использованы/переданы например в событие.
Делается это так:
// without arguments
delegate { Console.WriteLine("Hello World"); };
// or with arguments
delegate (int a, int b) { return a + b; };
Зачем?
Тут есть вполне внятный ответ и документации
An anonymous method can be converted to types such as System.Action and
System.Func<TResult>
types used as arguments to many methods.
Пример
Func<int, int, int> constant = delegate (int _, int _) { return 42; };
Console.WriteLine(constant(3, 4)); // output: 42
NOTE: То же самое с lambda expressions будет выглядеть чуть проще
Func<int, int, int> constant = (a, b) => 42;
Console.WriteLine(constant(3, 4)); // output: 42
Статические делегаты
Пример из документации
Func<int, int, int> sum = static delegate (int a, int b) { return a + b; };
Console.WriteLine(sum(10, 4)); // output: 14
статические делегаты не могут захватывать локальных переменных.
Java
Такого механизма как deletages в джаву не завозили. Передать код для выполнения в другую часть программы можно с помощью лямбд или использовать интерфейс и анонимный класс. Описанные методы работают как Java так и в C# и будут рассмотрены отдельно.