Понимание Лямбда-выражений и [закрытых] делегатов

14
задан user279521 19 July 2010 в 14:59
поделиться

5 ответов

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

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);
});

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

28
ответ дан 1 December 2019 в 06:47
поделиться

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

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

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

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

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

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

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 выглядеть одинаково, хотя на самом деле тип объекта, созданного с помощью лямбда-выражения, отличается.
6
ответ дан 1 December 2019 в 06:47
поделиться

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

string mystring = SomeObject.GetMyString();
AnotherObject.OnSomeEvent += (eventparams => 
{
  string newstring = string.Format(eventparams.Message, mystring);
  SomeService.PrintEvent(newstring);
}

Таким образом, mystring включается в делегат и может использоваться как переменная.

1
ответ дан 1 December 2019 в 06:47
поделиться

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

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 , которые обычно являются всем, что вам нужно.

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

3
ответ дан 1 December 2019 в 06:47
поделиться

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

    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
}
2
ответ дан 1 December 2019 в 06:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: