Когда это слишком много "лямбда-экшн"? - PullRequest
12 голосов
/ 12 ноября 2009

Я часто использую лямбды как своего рода "локальные функции", чтобы облегчить свою жизнь с помощью повторяющихся операций, подобных этим:

Func<string, string> GetText = (resource) => this.resourceManager.GetString(resource);
Func<float, object, string> FormatF1 = (f, o) => String.Format("{0:F1} {1}", f, o);
Func<float, object, string> FormatF2 = (f, o) => String.Format("{0:F2} {1}", f, o);

Вместо того, чтобы писать String.Format снова и снова, я могу с радостью сдуться с FormatF2, например. и сэкономить время, а когда мне нужно что-то изменить в форматировании, есть только одно место для внесения изменений. Особенно, когда мне нужны исключительно функции в данной функции, я очень не хочу превращать их в настоящую функцию. Хотя вышеприведенные лямбды были относительно небольшими ... иногда мне нравятся более крупные (ниже предполагается, что данные будут добавлены в таблицу для вывода на печать):

Action<string, string, string> AddSurfaceData = (resource, col, unit) => {
    renderTable.Cells[tableRowIndex, 0].Text = "\t" + this.GetText(resource);
    renderTable.Cells[tableRowIndex, 1].Text = FormatF2(paraHydReader.GetFloat(paraHydReader.GetOrdinal(col)), "");
    renderTable.Cells[tableRowIndex, 1].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Right;
    renderTable.Cells[tableRowIndex, 2].Text = " " + this.GetText(unit);
    renderTable.Cells[tableRowIndex, 2].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Left;
    ++tableRowIndex;
};

Опять же, мне это нужно часто, и все вышеперечисленные преимущества также применимы. Однако, как вы можете видеть, это довольно длинное для лямбда-выражения ... вопрос в том, когда вы рисуете линию? Моя последняя лямбда слишком большая? Какие существуют другие способы (кроме использования реальных функций или попытки помещения данных в контейнеры и их циклического выполнения), чтобы избежать повторной записи одного и того же кода?

Заранее спасибо

Christian

Ответы [ 8 ]

11 голосов
/ 12 ноября 2009

Это то, что вы используете потенциально много раз внутри метода, и только внутри этого метода. Мне нравится эта идея. Сделайте это, если это не затруднит чтение вашего кода. Я бы сказал, что вам следует пересмотреть вопрос, если вам трудно понять, что является содержанием лямбда-функции и каково реальное содержание метода. В этом случае может быть чище вытащить его отдельным отдельным методом.

В конце концов, это действительно вопрос вкуса ...

6 голосов
/ 12 ноября 2009

Я согласен с благоговением: для мелкомасштабного повторного использования внутри метода (или даже класса) это идеально. Как и string.Format примеры. Я использую это довольно часто. Это в основном то же самое, что и использование локальной переменной для промежуточного значения, которое вы используете более одного раза, , но затем для кода .

Ваш второй пример немного подталкивает. Каким-то образом это вызывает у меня ощущение, что закрытый метод AddSurfaceData (возможно, статический, в зависимости от его использования?) Подойдет лучше. Это, конечно, за пределами контекста, который у вас есть, поэтому используйте свое собственное здравое суждение.

4 голосов
/ 12 ноября 2009

Лямбда-метод - это анонимный метод.

Это означает, что вы не должны давать ему имя.

Если вы делаете это (в вашем случае вы присваиваете имя со ссылкой), это просто еще один способ объявить функцию.

В C # уже есть способ объявления функций, и это не лямбда-путь, который был добавлен уникально для передачи функций через параметры и возврата их в качестве возвращаемых значений.

Подумайте, например, в javascript:

function f(var1,var2,...,varX)
{
    some code
}

или

var f = function() {
    some code    
}

Другой синтаксис (почти) одно и то же.

Для получения дополнительной информации о том, почему это не одно и то же: Javascript: var functionName = function () {} против функции functionName () {}

Другой пример: в Haskell Вы можете определить две функции:

 function1 :: Int -> Int
 function1 x = x + 2

или

 function2 :: Int -> Int
 function2 = \x -> x + 2

То же самое (на этот раз я думаю, что это то же самое), другой синтаксис. Я предпочитаю первый, это более понятно.

C # 3.5, как и Javascript, имеет много функциональных влияний. Некоторые из них следует использовать с умом, ИМХО.

Кто-то сказал, что локальные лямбда-функции с присваиванием в ссылке являются хорошей заменой метода, определенного в другом методе, подобного предложению «let» или «where» в Haskell.

Я говорю «похоже», потому что у пар есть очень разная семантика, например, в Haskell я могу использовать имя функции, которое еще не объявлено, и определить его позже с «где», тогда как в C #, с назначением функции / ссылки I не могу этого сделать.

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

2 голосов
/ 12 ноября 2009

У меня нет проблем с длинным примером. Я вижу, что вы перепаковываете составные данные очень элегантно.

Это короткие, которые заставят ваших коллег исследовать преимущества добровольной институционализации. Пожалуйста, объявите некоторую константу для хранения вашей строки формата и используйте «эту String.Format-thing снова и снова». Как программист C #, я знаю, что это делает, не ища в другом месте функции домашнего запуска. Таким образом, когда мне нужно знать, как будет выглядеть отформатированная строка, я могу просто изучить константу.

2 голосов
/ 12 ноября 2009

+ 1 на nikie re DRY в целом хорош.

Я бы не стал использовать для них имена PascalCase.

Будьте осторожны - в большинстве случаев, у вас есть только метод извлечения в платье или потенциальный помощник или функция расширения. например, GetText - это метод, а FormatF* - это, вероятно, вспомогательный метод ...

2 голосов
/ 12 ноября 2009

Мне нравится идея. Я не вижу лучшего способа сохранить локальность кода без нарушения принципа СУХОЙ. И я думаю, что читать сложнее, только если вы не привыкли к лямбдам.

1 голос
/ 12 ноября 2009

Я согласен с volothamp в целом, но в дополнение ...

Подумайте о других людях, которые должны поддерживать ваш код. Я думаю, что это легче понять, чем ваш первый пример, и все же предлагает преимущества обслуживания, о которых вы упомянули:

String.Format(this.resourceManager.GetString("BasicFormat"), f, o);
String.Format(this.resourceManager.GetString("AdvancedFormat"), f, o);

И ваш второй пример, кажется, просто другой способ объявления функции. Я не вижу никакой пользы от объявления вспомогательного метода. И объявление вспомогательного метода будет более понятным для большинства программистов.

0 голосов
/ 12 ноября 2009

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

Я бы не использовал его для замены string.format.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...