С# Лямбда-выражения: зачем им их использовать?
Я быстро прочитал документацию Microsoft Lambda Expression.
Этот пример помог мне лучше понять, хотя:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
Тем не менее, я не понимаю, почему это такое новшество. Это просто метод, который умирает, когда "переменная метода" заканчивается, правильно? Почему я должен использовать это вместо реального метода?
Ответы
Ответ 1
Лямбда-выражения являются более простым синтаксисом для анонимных делегатов и могут использоваться везде, где может использоваться анонимный делегат. Однако противоположное утверждение неверно; лямбда-выражения могут быть преобразованы в деревья выражений, что позволяет использовать большую магию, такую как 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();
Лямбда-выражения и анонимные делегаты имеют преимущество перед написанием отдельной функции: они реализуют замыкания, которые могут позволить вам передать локальное состояние функции без добавления параметров в функцию или создания одноразовых объектов.
Деревья выражений - это очень мощная новая функция С# 3.0, которая позволяет API смотреть на структуру выражения вместо того, чтобы просто получать ссылка на метод, который может быть выполнен. API просто должен сделать параметр делегата параметром Expression<T>
, и компилятор будет генерировать дерево выражений из лямбда вместо анонимного делегата:
void Example(Predicate<int> aDelegate);
называется:
Example(x => x > 5);
становится:
void Example(Expression<Predicate<int>> expressionTree);
Последний получит представление абстрактного синтаксического дерева которое описывает выражение x > 5
. LINQ to SQL полагается на это поведение, чтобы иметь возможность превращать выражения С# в выражения SQL, необходимые для фильтрации/упорядочения/и т.д. На стороне сервера.
Ответ 2
Анонимные функции и выражения полезны для одноразовых методов, которые не приносят дополнительной работы, необходимой для создания полного метода.
Рассмотрим следующий пример:
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;
}
Они функционально эквивалентны.
Ответ 3
Я нашел их полезными в ситуации, когда я хотел объявить обработчик для некоторого события управления, используя другой элемент управления.
Для этого обычно вам нужно хранить ссылки на элементы управления в полях класса, чтобы вы могли использовать их другим способом, чем они были созданы.
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
Lambda очистил синтаксис анонимного делегата С# 2.0... например
Strings.Find(s => s == "hello");
Сделано в С# 2.0 следующим образом:
Strings.Find(delegate(String s) { return s == "hello"; });
Функционально они выполняют то же самое, это всего лишь более сжатый синтаксис.
Ответ 5
Это всего лишь один из способов использования выражения лямбда. Вы можете использовать выражение лямбда где угодно, вы можете использовать делегат. Это позволяет вам делать такие вещи:
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);
ИЗМЕНИТЬ
В С# 2.0 это можно сделать с помощью анонимного синтаксиса делегата:
strings.Find(delegate(String s) { return s == "hello"; });
Lambda значительно очистит этот синтаксис.
Ответ 6
Microsoft предоставила нам более чистый и удобный способ создания анонимных делегатов, называемых выражениями Lambda. Тем не менее, в этом выражении выражения не уделяется большого внимания. 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 или для генетическое программирование (AI). Несколько раз в моей карьере мне приходилось писать Excel-подобные функции, которые позволяли пользователям вводить простые выражения (дополнение, подпрограммы и т.д.) Для работы с доступными данными. В pre-.Net 3.5 мне приходилось прибегать к некоторому скриптовому языку, внешнему по отношению к С#, или ему приходилось использовать функциональные возможности кода для отражения, чтобы создать код .Net на лету. Теперь я бы использовал деревья выражений.
Ответ 7
Это сохраняет необходимость иметь методы, которые используются только один раз в определенном месте от определения вдали от места, где они используются. Хорошие применения - это компараторы для общих алгоритмов, таких как сортировка, где вы можете определить пользовательскую функцию сортировки, в которой вы вызываете сортировку, а не дальше, заставляя вас искать в другом месте, чтобы увидеть, что вы сортируете.
И это не настоящая новинка. LISP имеет функции лямбда в течение примерно 30 лет и более.
Ответ 8
Вы также можете найти использование лямбда-выражений в написании общих кодов, чтобы действовать на ваши методы.
Например: Общая функция для вычисления времени, полученного вызовом метода. (т.е. Action
здесь)
public static long Measure(Action action)
{
Stopwatch sw = new Stopwatch();
sw.Start();
action();
sw.Stop();
return sw.ElapsedMilliseconds;
}
И вы можете вызвать вышеуказанный метод, используя выражение лямбда следующим образом:
var timeTaken = Measure(() => yourMethod(param));
Выражение позволяет вам получать возвращаемое значение из вашего метода и из параметра param также
var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));
Ответ 9
В большинстве случаев вы используете только функциональность в одном месте, поэтому метод просто загромождает класс.
Ответ 10
Лямбда-выражение является кратким способом представления анонимного метода. Как анонимные методы, так и лямбда-выражения позволяют вам определить реализацию метода inline, однако анонимный метод явно требует определения типов параметров и типа возвращаемого значения для метода. Выражение Lambda использует функцию вывода типа С# 3.0, которая позволяет компилятору выводить тип переменной на основе контекста. Это очень удобно, потому что это позволяет нам много печатать!
Ответ 11
Выражение лямбда похоже на анонимный метод, написанный вместо экземпляра делегата.
delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;
Рассмотрим выражение лямбда x => x * x;
Значение входного параметра равно x (слева от = > )
Логика функции x * x (в правой части = > )
Код выражения лямбда может быть блоком оператора вместо выражения.
x => {return x * x;};
Пример
Примечание. Func
- предопределенный общий делегат.
Console.WriteLine(MyMethod(x => "Hi " + x));
public static string MyMethod(Func<string, string> strategy)
{
return strategy("Lijo").ToString();
}
Ссылки
Ответ 12
Это способ сделать небольшую операцию и установить ее очень близко к тому, где она используется (мало чем отличается от объявления переменной, близкой к ее используемой точке). Это должно сделать ваш код более читаемым. При анонимном выражении вы также значительно усложняете, чтобы кто-то нарушил ваш клиентский код, если он используется в другом месте и модифицирован, чтобы "улучшить" его.
Аналогично, зачем вам нужно использовать foreach? Вы можете делать все в foreach с помощью простого цикла или просто используя IEnumerable напрямую. Ответ: вам это не нужно, но это делает ваш код более удобочитаемым.
Ответ 13
Инновация заключается в типе безопасности и прозрачности. Хотя вы не объявляете типы лямбда-выражений, они выводятся и могут использоваться при поиске кода, статическом анализе, инструментах рефакторинга и отражении во время выполнения.
Например, прежде чем вы могли бы использовать SQL и могли бы получить инъекцию SQL-инъекции, поскольку хакер передал строку, где обычно ожидалось число. Теперь вы должны использовать выражение lambda LINQ, которое защищено от этого.
Построение LINQ API для чистых делегатов невозможно, поскольку для их оценки требуется комбинировать деревья выражений вместе.
В 2016 году большинство популярных языков lambda expression поддерживают, а С# был одним из пионеров в этой эволюции среди основных императивных языков.
Ответ 14
Это, пожалуй, лучшее объяснение того, почему использовать лямбда-выражения → https://youtu.be/j9nj5dTo54Q
В целом, это улучшает читаемость кода, уменьшает вероятность ошибок за счет повторного использования, а не репликации кода, а также оптимизацию рычагов, происходящих за кулисами.