Делегаты - это методы, которые вы можете использовать в качестве переменных, например строки и т. д. Например, вы можете объявить метод делегата с одним аргументом:
delegate void OneArgumentDelegate(string argument);
Он не делать что угодно, очень похоже на интерфейс. Если у вас есть метод в каком-либо классе с одним аргументом вроде этого:
void SomeMethod(string someArgument) {}
Он соответствует сигнатуре делегата и, таким образом, может быть назначен переменной его типа:
OneArgumentDelegate ThisIsAVariable = new OneArgumentDelegate(SomeMethod); OneArgumentDelegate ThisIsAlsoAVariable = SomeMethod; // Shorthand works too
Затем они могут быть передается в качестве аргументов методам и вызывается, например:
void Main() { DoStuff(PrintString); } void PrintString(string text) { Console.WriteLine(text); } void DoStuff(OneArgumentDelegate action) { action("Hello!"); }
Будет выведено Hello!
.
Лямбда-выражения являются сокращением для DoStuff (PrintString)
, поэтому вам не нужно создавать метод для каждой переменной делегата, которую вы собираетесь использовать. Вы «создаете» временный метод, который передается этому методу. Это работает так:
DoStuff(string text => Console.WriteLine(text)); // single line DoStuff(string text => // multi line { Console.WriteLine(text); Console.WriteLine(text); });
Лямбда-выражения - это просто сокращение, вы также можете создать отдельный метод и передать его. Надеюсь, теперь вы это лучше понимаете; -)
Делегат - это объект, содержащий ссылку на функцию. Несколько разных делегатов могут указывать на одну и ту же функцию. Тип делегата определяет след функции, на которую он может указывать.
Лямбда-выражение - это функция, у которой нет имени. Единственный способ выполнить эту функцию - иметь делегата , указывающего на функцию. Лямбда-выражения обычно определяются там, где вам нужен делегат функции с заданным следом. Это полезно для того, чтобы сделать код менее подробным и в то же время более описательным и гибким
. Я бы посоветовал вам использовать именованную функцию и ее делегата всякий раз, когда у вас есть код, который будет вызываться из разных мест. Типичным примером является прослушиватель событий, который вы хотите присоединить к нескольким производителям событий.
Еще один момент, который следует учитывать при написании отдельной функции, - это сложность кода. Если вы напишете целую программу внутри лямбда-выражения, это никому не поможет.
С другой стороны, вам часто требуется некоторая тривиальная обработка, которую вы хотите выполнить в режиме обратного вызова.Это тот момент, когда вам могут понравиться лямбда-выражения.
Что очень хорошо в лямбда-выражениях, так это то, что они наследуют область видимости, в которой были определены, так что вы можете легко использовать свои переменные внутри лямбда-выражения и, таким образом, передавать внутрь много информации. Однако будьте осторожны, см. Раздел «Примечания» это статья.
Labdas великолепно сочетается с LINQ.
В заключение я должен процитировать еще один раздел msdn, который необходимо прочитать:
Когда вы используете синтаксис на основе методов для вызова метода Where в классе Enumerable (как вы это делаете в LINQ to Objects и LINQ to XML) параметр является типом делегата System.Func. Лямбда-выражение - самый удобный способ создать этот делегат. Когда вы вызываете тот же метод, например, в классе System.Linq.Queryable (как и в LINQ to SQL), то тип параметра - это System.Linq.Expressions.Expression, где Func - это любые делегаты Func с числом до шестнадцати. входные параметры. Опять же, лямбда-выражение - это просто очень краткий способ построить это дерево выражений. Лямбда-выражения позволяют вызовам Where выглядеть одинаково, хотя на самом деле тип объекта, созданного с помощью лямбда-выражения, отличается.
Как говорили другие, лямбда-выражения - это синтаксис для создания встроенных и анонимных делегатов. Единственное, что вы можете делать с лямбдами, что невозможно с традиционными функциями, - это замыкания. Таким образом вы можете создавать функции во время выполнения с информацией времени выполнения:
string mystring = SomeObject.GetMyString();
AnotherObject.OnSomeEvent += (eventparams =>
{
string newstring = string.Format(eventparams.Message, mystring);
SomeService.PrintEvent(newstring);
}
Таким образом, mystring включается в делегат и может использоваться как переменная.
Никто не упомянул анонимных делегатов. Вы можете создавать делегатов на лету, не объявляя их:
public void Action(Func<int, int> func);
...
Action(delegate(int x) { return x*x; });
Это просто более подробная версия синтаксиса лямбда:
Action(x => x*x);
Также обратите внимание, что синтаксис лямбда имеет более агрессивный вывод типов. Другое отличие состоит в том, что лямбда-нотация может использоваться для объявления деревьев выражений:
public void Action(Expression<Func<int, int>>);
Action(x => x*x);
В этом случае вы получаете не функцию, а дерево синтаксического анализа , которое вы можете исследовать во время выполнения. Вот как, например, запросы linq строят свой sql.
править
Чтобы более прямо ответить на вопрос, когда использовать тот или иной тип:
Вам редко нужно самостоятельно объявлять новый тип делегата, хотя иногда это бывает полезно. Платформа предоставляет несколько типов Func <>
, а также Action
и Predicate
, которые обычно являются всем, что вам нужно.
При создании функции «на лету» нет никаких преимуществ в использовании синтаксиса анонимного делегата вместо синтаксиса лямбда. Поскольку лямбда-синтаксис более лаконичен и ориентирован на типы, предпочитайте его.
Делегат - это просто указатель на функцию. Он подобен "переменной", в которой можно сохранить адрес другой функции, которая будет вызвана
public class test {
Action<int> CallUserCode;
public test(Action<int> proc){
CallUserCode = proc;
}
void foo(){
int someValue = 0;
//do some stuff that needs to call the user procedure
CallUserCode(someValue);
}
}
Лямбда-выражения - это тоже делегат, который имеет упрощенный синтаксис и может "создавать" функции "inline". Таким образом, предыдущий пример будет вызван с помощью лямбды следующим образом.
void bar(){
var t = new test(x => { /* do something with the value i get from foo */});
t.foo(); //here function foo gets called, which will call 'do something' AND call my lambda expression
}