Локальная функция против лямбда C# 7.0
Я смотрю на новые реализации в C# 7.0 и мне интересно, что они реализовали локальные функции, но я не могу представить себе сценарий, в котором локальная функция была бы предпочтительнее лямбда-выражения, и в чем разница между ними.
Я понимаю, что лямбды -anonymous
функции между тем локальные функции не являются, но я не могу понять сценарий реального мира, где локальная функция имеет преимущества перед лямбда-выражения
любой пример был бы очень признателен. Спасибо.
3 ответа:
вы хотите вспомогательную функцию. Вы используете его только из одной функции, и он, вероятно, использует переменные и параметры типа, которые находятся в области действия в этой содержащей функции. С другой стороны, в отличие от лямбды вам не нужен объект первого класса, поэтому вы не хотите давать ему тип делегата и выделять фактический делегат объект. Также вы можете захотеть, чтобы он был рекурсивным или универсальным, или реализовать его как итератор.
чтобы расширить его еще немного, преимущества:
производительность.
при создании лямбды должен быть создан делегат, что в данном случае является ненужным выделением. Локальные функции на самом деле просто функции, никакие делегаты не нужны.
кроме того, локальные функции более эффективны при захвате локальных переменных: лямбды обычно захватывают переменные в класс, В то время как локальные функции можно использовать структуры (с помощью
ref
), что опять же позволяет избежать выделения.это также означает, что вызов функции-это дешевле, и они могут быть встроены, возможно, повысить производительность еще больше.
локальные функции могут быть рекурсивными.
лямбды тоже могут быть рекурсивными, но для этого требуется неудобный код, где вы сначала назначаете
null
переменной делегата, а затем лямбда. Локальные функции, естественно, могут быть рекурсивными (в том числе взаимно рекурсивными).локальные функции могут быть универсальными.
лямбды не могут быть универсальными, так как они должны быть присвоено переменной с конкретным типом (тип могут использовать общие переменные из внешней области видимости, но это не одно и то же).
локальные функции могут быть реализованы в виде итератора.
лямбды не могут использовать
yield return
(иyield break
) ключевое слово для реализацииIEnumerable<T>
-возвращение функции. Локальные функции.локальные функции выглядят лучше.
это не упоминается в приведенной выше цитате и может быть просто моим личным предубеждением, но я думаю, что нормальный синтаксис функции выглядит лучше, чем назначение лямбды переменной делегата. Местные функции также более лаконичны.
сравниваем:
int add(int x, int y) => x + y; Func<int, int, int> add = (x, y) => x + y;
кроме svick ответ есть еще одно преимущество для локальных функций:
Они могут быть определены в любом месте функции, даже послеreturn
заявление.public double DoMath(double a, double b) { var resultA = f(a); var resultB = f(b); return resultA + resultB; double f(double x) => 5 * x + 3; }
Я использую встроенные функции, чтобы избежать давления сборки мусора, особенно при работе с более длительными методами. Скажем, кто-то хотел бы получить 2 года или рыночные данные для данного символа тикера. Кроме того, можно упаковать много функциональности и бизнес-логики, если нужно.
что нужно сделать, это открыть сокет-соединение с сервером и перебрать данные, связывающие событие с событием. Можно думать об этом так же, как разработан класс, только один не пишет вспомогательные методы повсюду, которые действительно работают только для одного пика функциональности. ниже приведен пример того, как это может выглядеть, обратите внимание, что я использую переменные, а методы "helper" находятся ниже finally. В конце концов я красиво удаляю обработчики событий, если мой класс Exchange будет внешним / введенным, у меня не будет никакого ожидающего обработчика событий, зарегистрированного
void List<HistoricalData> RequestData(Ticker ticker, TimeSpan timeout) { var socket= new Exchange(ticker); bool done=false; socket.OnData += _onData; socket.OnDone += _onDone; var request= NextRequestNr(); var result = new List<HistoricalData>(); var start= DateTime.Now; socket.RequestHistoricalData(requestId:request:days:1); try { while(!done) { //stop when take to long…. if((DateTime.Now-start)>timeout) break; } return result; }finally { socket.OnData-=_onData; socket.OnDone-= _onDone; } void _OnData(object sender, HistoricalData data) { _result.Add(data); } void _onDone(object sender, EndEventArgs args) { if(args.ReqId==request ) done=true; } }
вы можете увидеть преимущества, как указано ниже, здесь вы можете посмотреть пример реализации. Надеюсь, что помогает объяснить преимущества.