#c# #delegates
#c# #делегаты
Вопрос:
Я просто экспериментировал и в итоге получил следующий фрагмент:
public static class Flow {
public static void Sequence(params Action[] steps) {
foreach (var step in steps)
step();
}
}
void Main() {
Flow.Sequence(() => F1(), () => F2());
Flow.Sequence(F1, F2); // <-- what makes this equiv to the line above?
}
void F1() { }
void F2() { }
Я не понимал, что одно только имя метода совпадает с действием.
Что делает это так?
Комментарии:
1. На самом деле они не эквивалентны; последнее лучше, потому что позволяет избежать дополнительного, пустого вызова метода. (которое, я допускаю, может быть оптимизировано, но все же; они не эквивалентны)
Ответ №1:
В C # делегаты — это не что иное, как указатели на методы. Они могут указывать на существующие методы в классе или вообще на независимые анонимные объекты делегирования.
Этот абзац из приведенной выше ссылки должен объяснить, что происходит в вашем коде:
Делегату может быть назначен любой метод, соответствующий сигнатуре делегата, которая состоит из возвращаемого типа и параметров. Это позволяет программно изменять вызовы методов, а также подключать новый код к существующим классам. Если вам известна подпись делегата, вы можете назначить свой собственный делегированный метод.
То есть при разрешении типов делегатов учитываются их сигнатуры, а не их имена.
В вашем случае ваши методы F1()
and F2()
, не принимающие параметров и ничего не возвращающие, имеют совпадающие подписи с Action
делегатом без параметров:
public delegate void Action();
Следовательно, они неявно преобразуются в Action
.
Если вы попытаетесь передать метод с другим типом возвращаемого значения или хотя бы одним параметром, вы получите ошибку времени компиляции, поскольку она не будет соответствовать сигнатуре Action
.
Комментарии:
1. И,, используя
F1
вместо() => F1()
, вызывает метод напрямую вместо добавления дополнительного делегата вокруг него.2. @xixonia: Не очень «напрямую», компилятор
Action
тоже создает экземпляр, онAction
создается из методаF1
напрямую. При использовании() => F1()
,Action
создается анонимный метод, в которомF1()
вызывается.3. @DannyChen, По крайней мере, более прямолинейно, чем нет. 🙂 Спасибо за исправление. Я волновался, что неправильно сформулировал это.
Ответ №2:
По сути, это своего рода то, что происходит в фоновом режиме:
void Main()
{
Flow.Sequence(new Action(delegate(){ F1(); }), new Action(delegate(){ F2(); }));
Flow.Sequence(new Action(F1), new Action(F2));
}
Они не СОВСЕМ эквивалентны, но они очень близки. Они будут выдавать одинаковые результаты во время выполнения, с той лишь разницей, что аргументы в первом вызове последовательности будут действием, которое вызывает анонимный метод, который затем вызывает статические методы F1 и F2; второй вызов последовательности будет действием, которое вызывает статические методы F1 и F2.
Я надеюсь, это поможет.
Комментарии:
1. Не беспокойтесь, я исправил это за вас.
Ответ №3:
Компилятор использует неявное преобразование из группы методов в делегат совместимого типа (в данном случае метод, возвращающий void, не принимающий аргументов), имена методов здесь неуместны.