Лямбда-выражения C#:Почему я должен их использовать?
Вопрос
Я быстро прочитал Лямбда-выражение Microsoft документация.
Однако такой пример помог мне лучше понять:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
Тем не менее, я не понимаю, почему это такое нововведение.Это просто метод, который умирает, когда заканчивается «переменная метода», верно?Почему я должен использовать это вместо реального метода?
Решение
Лямбда-выражения представляют собой более простой синтаксис для анонимных делегатов и могут использоваться везде, где может использоваться анонимный делегат.Однако обратное неверно;Лямбда-выражения можно преобразовать в деревья выражений, что позволяет реализовать множество чудес, таких как LINQ to SQL.
Ниже приведен пример LINQ для объектов выражение с использованием анонимных делегатов, а затем лямбда-выражения, чтобы показать, насколько они проще для глаз:
// 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();
Лямбда-выражения и анонимные делегаты имеют преимущество перед написанием отдельной функции:они реализуют закрытия что может позволить вам передать локальное состояние функции без добавления параметров к функции или созданию одноразовых объектов.
Деревья выражений — это очень мощная новая функция C# 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 использует это поведение, чтобы иметь возможность превращать выражения C# в выражения SQL, необходимые для фильтрации, упорядочивания и т. д.на стороне сервера.
Другие советы
Анонимные функции и выражения полезны для одноразовых методов, которые не требуют дополнительной работы, необходимой для создания полного метода.
Рассмотрим этот пример:
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;
}
Они функционально эквивалентны.
Я нашел их полезными в ситуации, когда я хотел объявить обработчик для события некоторого элемента управления, используя другой элемент управления. Чтобы сделать это обычно, вы должны хранить ссылки элементов управления в полях класса, чтобы вы могли использовать их в другом методе, чем они были созданы.
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;};
}
Гораздо проще.
Лямбда убрала синтаксис анонимного делегата в C # 2.0 ... например
Strings.Find(s => s == "hello");
Это было сделано в C # 2.0 следующим образом:
Strings.Find(delegate(String s) { return s == "hello"; });
Функционально, они делают то же самое, это просто более лаконичный синтаксис.
Это всего лишь один из способов использования лямбда-выражения.Вы можете использовать лямбда-выражение в любом месте вы можете использовать делегата.Это позволяет вам делать такие вещи:
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);
РЕДАКТИРОВАТЬ:
В C# 2.0 это можно было сделать с помощью синтаксиса анонимного делегата:
strings.Find(delegate(String s) { return s == "hello"; });
Lambda значительно очистила этот синтаксис.
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, и вы можете создавать свои собственные. Я думаю, вы можете видеть, что это может быть полезно, когда вы не знаете точно, каким должен быть алгоритм во время проектирования или компиляции. Я видел где-то пример использования этого для написания научного калькулятора. Вы также можете использовать его для байесовских систем или для генетическое программирование (AI). Несколько раз в моей карьере мне приходилось писать функции, подобные Excel, которые позволяли пользователям вводить простые выражения (сложение, подстановки и т. Д.) Для работы с доступными данными. В pre-.Net 3.5 мне приходилось прибегать к некоторому языку сценариев, внешнему по отношению к C #, или использовать рефлексию кода для отражения, чтобы создавать код .Net на лету. Теперь я бы использовал деревья выражений. Р>
Это избавляет от необходимости иметь методы, которые используются только один раз в определенном месте, от определения далеко от места, где они используются. Хорошее применение - это компараторы для общих алгоритмов, таких как сортировка, где вы можете затем определить пользовательскую функцию сортировки, где вы вызываете сортировку, а не дальше, заставляя вас искать в другом месте, чтобы увидеть, что вы сортируете.
И это не совсем инновация. LISP выполняет лямбда-функции в течение 30 или более лет.
Лямбда-выражение похоже на анонимный метод, написанный вместо экземпляра делегата.
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();
}
Рекомендации
Вы также можете найти использование лямбда-выражений при написании универсальных кодов для действий с вашими методами.
Например: универсальная функция для расчета времени, затраченного на вызов метода. (т.е. Действие
здесь)
public static long Measure(Action action)
{
Stopwatch sw = new Stopwatch();
sw.Start();
action();
sw.Stop();
return sw.ElapsedMilliseconds;
}
И вы можете вызвать вышеуказанный метод, используя лямбда-выражение следующим образом,
var timeTaken = Measure(() => yourMethod(param));
Выражение позволяет вам получить возвращаемое значение из вашего метода, а также из параметра
var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));
В большинстве случаев функциональность используется только в одном месте, поэтому создание метода просто загромождает класс.
Лямбда-выражение - это краткий способ представления анонимного метода. Как анонимные методы, так и лямбда-выражения позволяют определять встроенную реализацию метода, однако анонимный метод явно требует, чтобы вы определили типы параметров и тип возврата для метода. Лямбда-выражение использует функцию вывода типа C # 3.0, которая позволяет компилятору выводить тип переменной на основе контекста. Это очень удобно, потому что это экономит нам много печатать!
Это способ взять небольшую операцию и поместить ее очень близко к месту, где она используется (мало чем отличается от объявления переменной, близкой к точке ее использования). Это должно сделать ваш код более читабельным. Анонимизируя выражение, вы также значительно усложняете кому-то взламывать ваш клиентский код, если эта функция используется где-то еще и изменена для «улучшения». он.
Точно так же, почему вы должны использовать foreach? Вы можете делать все в foreach с простым циклом for или просто используя IEnumerable напрямую. Ответ: вам не нужно , но это делает ваш код более читабельным.
Инновация заключается в безопасности типов и прозрачности. Хотя вы не объявляете типы лямбда-выражений, они выводятся и могут использоваться для поиска кода, статического анализа, инструментов рефакторинга и отражения во время выполнения.
Например, прежде чем вы могли использовать SQL и получить атаку SQL-инъекцией, потому что хакер передал строку, где обычно ожидалось число. Теперь вы должны использовать лямбда-выражение LINQ, которое защищено от этого.
Построение LINQ API на чистых делегатах невозможно, поскольку для его оценки требуется объединить деревья выражений вместе.
В 2016 году большинство популярных языков имеют лямбда-выражение , и C # был одним из пионеры в этой эволюции среди основных императивных языков.
Это, пожалуй, лучшее объяснение того, зачем использовать лямбда-выражения - > https://youtu.be/j9nj5dTo54Q
Итак, это улучшение читабельности кода, снижение вероятности возникновения ошибок за счет повторного использования, а не репликации кода, и использование оптимизации за кулисами. Р>