Вот в этом вопросе поднимается вопрос о планируемых нововведения в c# версии 7.
В частности меня заинтересовали так называемые локальные функции
В ответе @VladD есть пример как может быть использована локальная функция
IEnumerable
но мне кажется данный пример слегка натянутым, в данном случае можно было бы наверно и обойтись без функции Inner()
Так же мне непонятно следующее высказывание:
По поводу локальных функций, мне кажется, часто, наоборот, приватные функции классов используются как костыль на отсутствие локальных функций. Часто в приватную функцию выносится хелпер из одной функции, не имеющий значения внутри класса. Локальная функция — более правильный путь для таких функций.
У себя в коде я оформляю отдельными методами код на основании следующих правил:
Функционал который может быть повторно использован;
Вынесения функционала в отдельный метод что бы поддерживать стройность функции;
Прочее
Например:
public IEnumerable
private IEnumerable
Если я правильно понял то тогда в новой версии языка функции getRecipientsForNewRequest(int requestId), getRecipientsForClosedRequest(int requestId) можно будет реализовать внутри главной функции GetPhonesForNotice(int requestId) но я не понимаю чем это правильней/лучше текущего варианта?
Ответ
Мне кажется вот как.
Вопрос не в технической стороне дела. (Хотя технические отличия есть, они приведены в конце ответа.) С технической стороны, можно организовать такую же приватную функцию, в которую передавать все параметры явно. А если внутренняя функция должна иметь меньше параметров (например, из-за того, что требуется специфическая сигнатура), можно построить closure. Все технические вопросы решаемы и в рамках старых возможностей. (Точно так же как можно было бы обойтись без свойств и использовать пару функций, без классов, и передавать this в методы явно и т. д.)
Дело в том, что мы хотим не загрязнять хелпер-функциями класс, а положить их внутри того, к чему они относятся. Это полная аналогия идеи о том, что класс должен содержать всё то, что необходимо ему для работы, и не требовать «внешнего» управления. Точно так же и тут, функция содержит внутри себя то, что нужно для работы, а приватные вспомогательные методы получаются необходимы лишь там, где они не ограничены смыслом одной функции — то есть, там, где они осмысленны в рамках всего класса
С таким подходом, да, локальные переменные некоторым образом заменяют поля класса, так что в ситуациях, когда раньше вам нужно было создавать внутренний класс и вызывать в нём методы, теперь можно сделать то же самое удобнее с локальными функциями.
Кроме того, уменьшение обвязочного кода наподобие неявной передачи переменных всегда важно, так обвязочный код — возможность ошибиться.
В качестве ещё одного мотивирующего примера:
void SortBy expr, bool ascending)
{
int comparerAscending(T t1, T t2)
{
return expr(t1).Compare(expr(t2));
}
int comparerDescending(T t1, T t2)
{
return expr(t2).Compare(expr(t1));
}
list.Sort(ascending ? comparerAscending : comparerDescending);
}
Без локальных функций вам пришлось бы создавать внутренние делегаты.
Ещё один сценарий, в котором внутренние функции могут быть полезны — кодогенерация. Если вы генерируете вспомогательную функцию, вы можете случайно попасть на уже занятое имя, вы ведь не знаете, что там в остальной части класса. Если вспомогательная функция «упакована» в другую функцию, этой проблемы не возникает.
Дополнение: Давайте рассмотрим, кроме логических, отличия между локальными функциями и уже существующими средствами языка.
Отличие от приватной нелокальной функции состоит, кроме «скрытого» имени, в том, что локальная функция «видит» переменные, объявленные в охватывающей функции до неё. Таким образом, отпадает необходимость передавать параметры в локальную функцию явно, и значит, мы можем более свободно управлять её сигнатурой. (Это может быть важно, см. пример с SortBy.)
Отличие локальной функции от аналогичного локально объявленного делегата с лямбда-функцией состоит в том, что
делегатная переменная может быть переопределена, имя локальной функции не может быть перепривязано
лямбда-функции требуют хитрого синтаксиса для реализации рекурсивного вызова, который таки ломается при последующем изменении делегатной переменной (Y-комбинатор не предлагать!), у локальных функций проблем не возникает
лямбда-функция не может быть генератором (yield return)
вы не можете объявить обобщённую лямбда функцию (Func
Литература: C# Design Notes for May 20, 2015
Комментариев нет:
Отправить комментарий