Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.84/449: Рейтинг темы: голосов - 449, средняя оценка - 4.84
 Аватар для Mikant
1322 / 995 / 127
Регистрация: 08.12.2009
Сообщений: 1,299

Лямбда - выражения

14.02.2010, 16:10. Показов 85996. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Довольно часто прихожане на нашем форуме просят помочь им в написании кода. Как правило первым моментальным ответом на это следует однострочный код с использованием LINQ, лямбда-выражений, методов расширения. Уже потом по просьбе разъяснить это решение форумчане выписывают сотню строк кода, только чтобы разъяснить суть вышеприведенных систем.

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

Итак, сформулируем задачу: у нас есть класс MyClass,
C#
1
2
3
4
    public class MyClass {
        public int IntegerValue { get; set; }
        public string StringValue { get; set; }
    }
коллекция его экземпляров:
C#
1
2
3
4
5
6
7
8
9
10
11
12
        private List<MyClass> myCollection = new List<MyClass>() {
            new MyClass(){ IntegerValue=0, StringValue="qwe" },
            new MyClass(){ IntegerValue=1, StringValue="wer" },
            new MyClass(){ IntegerValue=2, StringValue="ert" },
            new MyClass(){ IntegerValue=3, StringValue="rty" },
            new MyClass(){ IntegerValue=4, StringValue="tyu" },
            new MyClass(){ IntegerValue=5, StringValue="yui" },
            new MyClass(){ IntegerValue=6, StringValue="uio" },
            new MyClass(){ IntegerValue=7, StringValue="iop" },
            new MyClass(){ IntegerValue=8, StringValue="opq" },
            new MyClass(){ IntegerValue=9, StringValue="pqw" },
        };
и нам требуется выбрать из неё элементы, у которых IntegerValue меньше 5

Программист не задумываясь сразу напишет строку:
C#
1
var found = myCollection.FindAll(mc => mc.IntegerValue < 5);
с левой частью все ещё более-менее понятно: var на этапе компиляции просто превратится в List<MyClass> (так как метод FindAll имеет именно такой возвращаемый тип), а вот с правой возникают сложности. Естественно Вы можете сказать, что такую выборку можно сделать и в простом цикле,
C#
1
2
3
4
            List<MyClass> found = new List<MyClass>();
            for (int i = 0; i < myCollection.Count; i++)
                if (myCollection[i].IntegerValue < 5)
                    found.Add(myCollection[i]);
но как видно из примера, это займет уже в четыре раза большее количество строк, а самое главное - потеряется универсальность кода. Тем более ситуация усложнится при манипуляциях с большими коллекциями, где выборку надо делать по множеству критериев.

рассмотрим же метод FindAll с поверхности: он требует на вход некий Predicate<T> match, который возвращает значение типа bool (в нашем случае - true, если IntegerValue меньше 5)

внутри же этот метод выглядит следующим образом:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
        public List<T> FindAll(Predicate<T> match) { 
            if( match == null) {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
            }
 
            List<T> list = new List<T>(); 
            for(int i = 0 ; i < _size; i++) {
                if(match(_items[i])) {
                    list.Add(_items[i]);
                }
            }
            return list;
        }
таким же образом как я описал выше создается новая коллекция, затем в цикле проверяется условие предиката и, если оно выполняется, в список добавляется новый элемент.

так что же значила эта строка?
C#
1
mc => mc.IntegerValue < 5
или, что то же самое
C#
1
(mc) => { return mc.IntegerValue < 5; }
Правильно - очень заковыристый способ создания делегата предиката!

Обойтись без этой конструкции можно добавив в код следующий метод:
C#
1
2
3
4
        private static bool IntegerValueLessThanFive(MyClass mc) {
            if (mc.IntegerValue < 5) return true;
            return false;
        }
И производить поиск следующим способом:
C#
1
2
Predicate<MyClass> predicate = new Predicate<MyClass>(IntegerValueLessThanFive);
List<MyClass> found = myCollection.FindAll(predicate);
либо так:
C#
1
List<MyClass> found = myCollection.FindAll(IntegerValueLessThanFive);
так как обертка предиката будет создана автоматически на этапе компиляции

К сожалению, приведенный выше код занимает намного больше места, явно объявлен метод для простейшей выборки. Зато он сработает в самой старой спецификации C# - да, раньше только так и писали.

С выходом C# 2.0 в языке появились так называемые анонимные делегаты. Поясню: метод IntegerValueLessThanFive имеет свое имя но в действительности будет использован только в FindAll, следовательно, зачем ему вообще имя - ссылки достаточно? Тип Predicate<T> в системе объявлен следующим образом:
C#
1
public delegate bool Predicate<T>(T value);

Не по теме:

Для тех кто не знает, делегат - ссылка на функцию.



И чтобы не пользоваться конструкцией
C#
1
public static Predicate<MyClass> IntegerValueLessThanFivePredicate = new Predicate<MyClass>(IntegerValueLessThanFive);
или создавать предикат в коде (до поиска) появилась возможность объявления тел методов, как анонимных делегатов:
C#
1
List<MyClass> found = myCollection.FindAll(delegate(MyClass mc) { return mc.IntegerValue < 5; });
Так намного компактнее, правда?

В C# 3.0 вместе с LINQ пришли лямбда-выражения.
Для математики лямбда-исчисление - огромный раздел, но для прикладного программирования лямбда-выражения - не более чем простой способ объявления анонимных делегатов:
C#
1
2
3
Predicate<MyClass> p1 = (mc) => { return mc.IntegerValue < 5; };
// вместо
Predicate<MyClass> p2 = delegate(MyClass mc) { return mc.IntegerValue < 5; };
Обратите внимание, что в первом случае у mc отсутствует тип (его можно дописать так "(MyClass mc)=>...") - компилятор сам разрешает такие деликатные ситуации, а нам не требуется выписывать лишние символы.

Конечно свежеиспеченный предикат можно использовать и как обычный метод:
C#
1
2
Predicate<MyClass> pred = (MyClass mc) => { return mc.IntegerValue < 5; };
 bool b = pred.Invoke(myCollection[0]);
С помощью лямбда-выражений можно к примеру объявлять поведение элементов управления в одном методе:
C#
1
2
3
4
5
6
            Action<object, EventArgs> changeText = (object sender, EventArgs e) => {
                this.Text = (sender as Control).Text;
            };
 
            button1.Click += new EventHandler(changeText);
            button2.Click += new EventHandler(changeText);
Их малые размеры позволяют создавать гибкую систему методов внутри других методов и строить длинные деревья выражений.

Таким образом, не надо бояться таких аккуратных записей, теперь Вы знаете, как это работает
C#
1
2
3
            List<MyClass> found = myCollection.FindAll(mc => {
                mc.IntegerValue < 5 && mc.StringValue.Contains("a");
            });
Рекомендую статью HIMen , где рассказано про "нововведения" C# 3.0 , такие как LINQ и методы расширения.

Спасибо за внимание!
136
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.02.2010, 16:10
Ответы с готовыми решениями:

Лямбда-выражения
Собственно,какие у нее плюсы перед анонимными методами,кроме конечно того,что теперь еще меньше кода писать надо?

Упрощение кода Лямбда-выражения и цыкл
Здравствуйте, подскажите пожалуйста можно ли как-то упростить данный код (избавится от цикла, используя лямбда-выражения): static...

Подскажите по лямбда выражениям
Тут http://msdn.microsoft.com/ru-ru/library/bb397687(v=VS.90).aspx написанно вот такое Но почему если я делаю так: ...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
14.02.2010, 16:10
Помогаю со студенческими работами здесь

Вложенный Linq лямбда не работает
Вложенный Linq лямбда не работает. Когда вытаскиваю внутренний запрос за пределы наружной лямбды все хорошо.. private static...

Как написать асинхронное лямбда-выражение?
Вопрос в заголовке.

Лямбда выражение и LINQ. Последовательность без повторений
Как сделать что бы результирующая последовательность имела не повторяющие числа ?

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

Лямбда выражение в качестве параметра метода. Как получить свойство с которым производится операция?
Добрый день! Нужно в методе принимать лямбду: obj.Get(x=&gt;x.ParentId==5); Как мне из этой лямбды в методе Get получить...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Закрытая тема Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru