2008-10-03 4 views
273

Я быстро прочитал документацию Microsoft Lambda Expression.C# Лямбда-выражения: зачем им их использовать?

Такого рода пример помог мне лучше понять, хотя:

delegate int del(int i); 
del myDelegate = x => x * x; 
int j = myDelegate(5); //j = 25 

Тем не менее, я не понимаю, почему это такое новшество. Это просто метод, который умирает, когда «переменная метода» заканчивается, правильно? Почему я должен использовать это вместо реального метода?

ответ

256

Lambda expressions - более простой синтаксис для анонимных делегатов и может использоваться везде, где может использоваться анонимный делегат. Однако противоположное утверждение неверно; лямбда-выражения могут быть преобразованы в деревья выражений, что позволяет использовать большую магию, такую ​​как LINQ to SQL.

Ниже приведен пример выражения LINQ to Objects с помощью анонимных делегатов, то лямбда-выражения, чтобы показать, насколько легче на глаз они:

// anonymous delegate 
var evens = Enumerable 
       .Range(1, 100) 
       .Where(delegate(int x) { return (x % 2) == 0; }) 
       .ToList(); 

// lambda expression 
var evens = Enumerable 
       .Range(1, 100) 
       .Where(x => (x % 2) == 0) 
       .ToList(); 

Лямбда-выражения и анонимные делегаты имеют преимущество перед писать отдельную функцию : они реализуют closures, что может позволить вам pass local state to the function without adding parameters функции или создавать одноразовые объекты.

Expression trees - это очень мощная новая функция C# 3.0, которая позволяет API просматривать структуру выражения вместо того, чтобы просто ссылаться на метод, который может быть выполнен. API просто должен сделать параметр делегата в Expression<T> параметра и компилятор сгенерирует дерево выражений из лямбда вместо анонимного делегата:

void Example(Predicate<int> aDelegate); 

называется как:

Example(x => x > 5); 

становится:

void Example(Expression<Predicate<int>> expressionTree); 

Последний получит представление abstract syntax tree, которое описывает выражение x > 5. LINQ to SQL полагается на это поведение, чтобы иметь возможность превращать выражения C# в выражения SQL, необходимые для фильтрации/упорядочения/и т. Д. На стороне сервера. очищены анонимный синтаксис делегат

4

Много раз, вы используете только функциональность в одном месте, поэтому метод просто загромождает класс.

11

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

И это не инновация. LISP имеет функции лямбда в течение 30 или более лет.

124

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

Рассмотрим следующий пример:

string person = people.Find(person => person.Contains("Joe")); 

против

public string FindPerson(string nameContains, List<string> persons) 
{ 
    foreach (string person in persons) 
     if (person.Contains(nameContains)) 
      return person; 
    return null; 
} 

Эти функционально эквивалентны.

+6

Как бы найти метод Find() для обработки этого лямбда-выражения? – 2008-10-03 15:16:51

+1

Предикат - это то, что ожидает метод Find. – 2008-10-03 15:19:28

+1

Поскольку мое выражение лямбда соответствует контракту на предикат , метод Find() принимает его. – 2008-10-03 15:21:01

3

Это способ сделать небольшую операцию и установить ее очень близко к тому, где она используется (в отличие от объявления переменной, близкой к ее используемой точке). Это должно сделать ваш код более читаемым. При анонимном выражении вы также значительно усложняете, чтобы кто-то нарушил ваш клиентский код, если он используется в другом месте и модифицирован, чтобы «улучшить» его.

Аналогичным образом, зачем вам использовать foreach? Вы можете делать все в foreach с помощью простого цикла или просто используя IEnumerable напрямую. Ответ: вы не нужно, но это делает ваш код более читаемым.

4

Лямбда-выражение является кратким способом представления анонимного метода. Как анонимные методы, так и лямбда-выражения позволяют вам определить реализацию метода inline, однако анонимный метод явно требует определения типов параметров и типа возвращаемого значения для метода. Выражение Lambda использует функцию вывода типа C# 3.0, которая позволяет компилятору выводить тип переменной на основе контекста. Это очень удобно, потому что это позволяет нам много печатать!

27

Это всего лишь один из способов использования выражения лямбда. Вы можете использовать выражение лямбда в любом месте, вы можете использовать делегат. Это позволяет делать такие вещи, как это:

List<string> strings = new List<string>(); 
strings.Add("Good"); 
strings.Add("Morning") 
strings.Add("Starshine"); 
strings.Add("The"); 
strings.Add("Earth"); 
strings.Add("says"); 
strings.Add("hello"); 

strings.Find(s => s == "hello"); 

Этот код будет искать список для записи, которая соответствует слову «привет».Другой способ сделать это на самом деле передать делегат методу Find, например:

List<string> strings = new List<string>(); 
strings.Add("Good"); 
strings.Add("Morning") 
strings.Add("Starshine"); 
strings.Add("The"); 
strings.Add("Earth"); 
strings.Add("says"); 
strings.Add("hello"); 

private static bool FindHello(String s) 
{ 
    return s == "hello"; 
} 

strings.Find(FindHello); 

EDIT:

В C# 2.0, это может быть сделано с помощью анонимного синтаксиса делегата:

strings.Find(delegate(String s) { return s == "hello"; }); 

Lambda значительно убирает этот синтаксис.

33

Lambda в C# 2.0 в ... например

Strings.Find(s => s == "hello"); 

было сделано в C# 2.0 вроде этого:

Strings.Find(delegate(String s) { return s == "hello"; }); 

Функционально, они делают одно и то же, это всего лишь более сжатый синтаксис.

21

Microsoft предоставила нам более чистый и удобный способ создания анонимных делегатов, называемых выражениями лямбда. Тем не менее, не так много внимания уделяется выражениям этой инструкции. Microsoft выпустила целое пространство имен, System.Linq.Expressions, которое содержит классы для создания деревьев выражений на основе лямбда-выражений. Деревья выражений состоят из объектов, представляющих логику. Например, x = y + z - выражение, которое может быть частью дерева выражений в .Net.Рассмотрим следующий (простой) пример:

using System; 
using System.Linq; 
using System.Linq.Expressions; 


namespace ExpressionTreeThingy 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object 
      var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime 
      Console.WriteLine(del(5)); //we are just invoking a delegate at this point 
      Console.ReadKey(); 
     } 
    } 
} 

Этот пример тривиален. И я уверен, что вы думаете: «Это бесполезно, поскольку я мог бы непосредственно создать делегат вместо того, чтобы создавать выражение и компилировать его во время выполнения». И ты был бы прав. Но это обеспечивает основу для деревьев выражений. В пространствах имен Expressions имеется несколько выражений, и вы можете создавать свои собственные. Я думаю, вы можете видеть, что это может быть полезно, когда вы не знаете точно, какой алгоритм должен быть во время проектирования или компиляции. Я видел пример где-то, чтобы использовать это, чтобы написать научный калькулятор. Вы также можете использовать его для систем Bayesian или для genetic programming (AI). Несколько раз в моей карьере мне приходилось писать Excel-подобные функции, которые позволяли пользователям вводить простые выражения (дополнение, подпрограммы и т. Д.) Для работы с доступными данными. В pre-.Net 3.5 мне приходилось прибегать к некоторому скриптовому языку, внешнему по отношению к C#, или ему приходилось использовать функциональные возможности кода для отражения, чтобы создать код .Net на лету. Теперь я бы использовал деревья выражений.

79

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

private ComboBox combo; 
private Label label; 

public CreateControls() 
{ 
    combo = new ComboBox(); 
    label = new Label(); 
    //some initializing code 
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged); 
} 

void combo_SelectedIndexChanged(object sender, EventArgs e) 
{ 
    label.Text = combo.SelectedValue; 
} 

благодаря лямбда-выражений, которые вы можете использовать его как это:

public CreateControls() 
{ 
    ComboBox combo = new ComboBox(); 
    Label label = new Label(); 
    //some initializing code 
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;}; 
} 

Намного проще.

4

Выражение лямбда подобно анонимному методу, написанному вместо экземпляра делегата.

delegate int MyDelagate (int i); 
MyDelagate delSquareFunction = x => x * x; 

Рассмотрим лямбда-выражение: x => x * x;

The input parameter value is x (on the left side of =>)

The function logic is x * x (on the right side of =>)

код лямбда-выражение может быть участок_программы вместо выражения.

x => {return x * x;}; 

Пример

Примечание: Func является предопределенным Универсальный делегат.

Console.WriteLine(MyMethod(x => "Hi " + x)); 

    public static string MyMethod(Func<string, string> strategy) 
    { 
     return strategy("Lijo").ToString(); 
    } 

Ссылки

  1. How can a delegate & interface be used interchangeably?
5

Вы можете также найти применение лямбда-выражений в письменном виде общие коды действовать на своих методах.

Например: общая функция для вычисления времени, полученного вызовом метода. (Т.е.Action здесь)

public static long Measure(Action action) 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    action(); 
    sw.Stop(); 
    return sw.ElapsedMilliseconds; 
} 

И вы можете вызвать выше метод с использованием лямбда-выражения следующим образом,

var timeTaken = Measure(() => yourMethod(param)); 

Expression позволяет получить возвращаемое значение из метода и из парам, а

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam)); 
0

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

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

Построение API LINQ для чистых делегатов невозможно, поскольку для их оценки требуется комбинировать деревья выражений вместе.

В 2016 году большинство популярных языков поддерживают lambda expression, а C# был одним из пионеров в этой эволюции среди основных императивных языков.

0

Это, пожалуй, лучшие объяснения о том, почему использовать лямбда-выражения ->https://youtu.be/j9nj5dTo54Q

В целом, это, чтобы улучшить читаемость кода, уменьшить вероятность ошибок при повторном использовании, а не копировать код и оптимизация рычагов происходит за кулисами ,