Когда это слишком много "лямбда-действий"?
Я часто нахожу себя использующим лямбды как своего рода "локальные функции", чтобы облегчить мою жизнь повторными операциями, такими как:
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
Ответы
Ответ 1
Это то, что вы используете потенциально много раз в рамках метода, и только это внутри этого метода. Мне нравится эта идея. Сделайте это, если это не делает ваш код трудно читать. Я бы сказал, что вам следует пересмотреть, если вам трудно понять, что является содержанием лямбда-функции, чем то, что является реальным содержанием метода. В этом случае может быть более чистым вытащить его в отдельном частном методе.
В конце концов, это действительно вопрос вкуса...
Ответ 2
Я согласен с благоговением: для малогабаритного повторного использования внутри метода (или даже класса) это идеально. Как и примеры string.Format
. Я использую это довольно часто. Это в основном то же самое, что использование локальной переменной для промежуточного значения, которое вы используете более одного раза, но затем для кода.
Ваш второй пример, похоже, немного подталкивает его. Почему-то это дает мне ощущение, что частный метод AddSurfaceData
(возможно, статический, в зависимости от его использования?) Будет лучше подходит. Это, конечно, вне контекста, который у вас есть, поэтому используйте свое собственное мнение.
Ответ 3
Лямбда-метод - анонимный метод.
Это означает, что вы не должны указывать его имя.
Если вы это делаете (в вашем случае вы назначаете имя своей ссылкой), это просто еще один способ объявить функцию.
У С# уже есть способ объявить функции, и это не лямбда-путь, который был добавлен
однозначно передавать функции через параметры и возвращает их как возвращаемые значения.
Подумайте, например, в javascript:
function f(var1,var2,...,varX)
{
some code
}
или
var f = function() {
some code
}
Разный синтаксис (почти) то же самое.
Для получения дополнительной информации о том, почему это не одно и то же: Javascript: var functionName = function() {} vs function functionName() {}
Другой пример: в Haskell Вы можете определить две функции:
function1 :: Int -> Int
function1 x = x + 2
или
function2 :: Int -> Int
function2 = \x -> x + 2
То же самое (на этот раз я думаю, это то же самое), различный синтаксис. Я предпочитаю первый, это более понятно.
С# 3.5, как Javascript, имеет много функциональных влияний. Некоторые из них должны быть разумно использованы, ИМХО.
Кто-то сказал, что локальные лямбда-функции с присваиванием в ссылке являются хорошей заменой для метода, определенного в другом методе, аналогичном предложению "let" или "where" в Haskell.
Я говорю "похоже", потому что у twos есть очень разные семантики, например, в Haskell я могу использовать имя функции, которое еще не объявлено, и определить позже с "where", а в С#, с назначением функции/ссылки я не может этого сделать.
Кстати, я думаю, что это хорошая идея, я не запрещаю это использование лямбда-функции, я просто хочу заставить людей подумать об этом.
Каждый язык имеет свой механизм абстракции, использует его с умом.
Ответ 4
Мне нравится идея. Я не вижу лучшего способа сохранить местонахождение кода без нарушения принципа DRY. И я думаю, что это только труднее читать, если вы не привыкли к лямбдам.
Ответ 5
+1 на nikie re DRY является хорошим вообще.
Я бы не использовал PascalCase для них.
Будьте осторожны, хотя в большинстве случаев материал, который у вас есть, - это всего лишь метод извлечения в одежде или потенциальный помощник или функция расширения. например, GetText
является методом и FormatF*
, вероятно, является вспомогательным методом...
Ответ 6
У меня нет проблем с длинным примером. Я вижу, что вы очень элегантно переупаковываете составные данные.
Это короткие, которые побудят ваших коллег расследовать преимущества добровольной институционализации. Пожалуйста, объявляйте какую-то константу, чтобы держать вашу строку формата и использовать "эту String.Format-вещь снова и снова". Как программист на С#, я знаю, что это делает, не глядя в другое место для домашних функций. Таким образом, когда мне нужно знать, как будет выглядеть форматированная строка, я могу просто изучить константу.
Ответ 7
Я согласен с volothamp в целом, но кроме того...
Подумайте о других людях, которые должны поддерживать ваш код. Я думаю, что это легче понять, чем ваш первый пример, и по-прежнему предлагает преимущества обслуживания, которые вы упоминаете:
String.Format(this.resourceManager.GetString("BasicFormat"), f, o);
String.Format(this.resourceManager.GetString("AdvancedFormat"), f, o);
И ваш второй пример - это просто другой способ объявить функцию. Я не вижу полезной пользы от объявления вспомогательного метода. И объявление вспомогательного метода будет более понятным большинству кодеров.
Ответ 8
Я лично считаю, что он не в хорошем вкусе использовать лямбда-функции, когда в этом нет необходимости. Я лично не использую лямбда-функцию для замены простых нескольких строк процедурного кода. Лямбда-функции предлагают множество улучшений, но делают код более сложным для чтения.
Я бы не использовал его для замены string.format.