Использование лямбда-выражения в сравнении с закрытым методом

Я прочитал ответ на вопрос о переполнении стека, который содержал следующий предложенный код:

Action<Exception> logAndEat = ex => 
{  
    // Log Error and eat it
};

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

У меня вопрос: в чем преимущество (если оно есть) использования лямбда-выражения для LogAndEat, в отличие от (на мой взгляд, более простого и более очевидного) частного метода, который выглядит следующим образом:

private void LogAndEat(Exception ex)
{
    // Log Error and eat it
}

Редактировать: Спасибо за ответы на этот вопрос, но просто более четко сформулирую мой фундаментальный вопрос: какой подход лучше / будет лучше Вы рекомендуете в этом случае? Лямбда-выражение или закрытый метод?

18
задан abatishchev 20 August 2010 в 09:58
поделиться

7 ответов

Спасибо всем за отличные ответы, за которые я проголосовал, но я решил обобщить их, чтобы попытаться отразить плюсы и минусы в одном ответе.

Плюсы использования лямбда-выражения (LE) вместо закрытого метода:

  • Ограничение LE ограничено методом, в котором оно объявлено, поэтому, если оно используется только этим методом, то это намерение делается явным с помощью лямбда-выражения (хотя можно передать делегата в LE, все же можно утверждать, что целью объявления LE в методе является то, что LE ограничивается методом). То есть быть явным с точки зрения ожидаемого использования.
  • Лямбда-выражения ведут себя как замыкания, поэтому они могут получить доступ к переменным в области действия метода, в котором они объявлены. Это может быть более аккуратно, чем передача большого количества параметров частному методу.
  • В противном случае переменные, захваченные LE, были бы параметрами частного метода, и это можно использовать для каррирования.

Минусы использования лямбда-выражения вместо приватного метода:

  • Поскольку LE может обращаться к переменным, относящимся к методу, в котором они содержатся, невозможно изменить код в вызывающем методе во время отладки.

Существует также более субъективная проблема удобства сопровождения, и можно утверждать, что LE не так хорошо понимается большинством разработчиков, как частный метод, и поэтому его несколько сложнее поддерживать.Можно также утверждать, что LE повышает удобство сопровождения, поскольку он инкапсулирован в методе, в котором он вызывается, а не в частном методе, который виден всему классу.

1
ответ дан 30 November 2019 в 08:10
поделиться

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

Частный метод может быть вызван из любого метода в том же классе, в то время как лямбда, подобная этой, является локальной для текущего метода и поэтому явно используется только в этом контексте.

Это действительно единственное преимущество, о котором я могу думать, - ясность с точки зрения ожидаемого использования.

13
ответ дан 30 November 2019 в 08:10
поделиться

Переменные, захваченные logAndEat , в противном случае были бы параметрами для метода LogAndEat . Вы можете считать это формой карри.

9
ответ дан 30 November 2019 в 08:10
поделиться

LogAndEat может ссылаться на частные поля внутри функции, в которой он определен. Итак:

private bool caughtException; 

Action<Exception> logAndEat = ex => 
    {  
        caughtException = true;
    };

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

if (caughtException)
{
    Console.Writeline("Ma, I caught an exception!");
}

Это банальный пример (!), Но потенциально это может быть намного аккуратнее, чем передача кучи параметров частному методу.

3
ответ дан 30 November 2019 в 08:10
поделиться

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

Я не думаю, что использование лямбды вместо функции повлияет на производительность

.
0
ответ дан 30 November 2019 в 08:10
поделиться

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

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

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

1
ответ дан 30 November 2019 в 08:10
поделиться

Чтобы понять, лучше ли использовать лямбда-выражение (как я сделал в исходном ответе ) или использовать «правильный» метод, нам нужно принять решение на основе о том, насколько многоразовым является код обработки общих ошибок.

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

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

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

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

Теперь, возвращаясь к вопросу, почему я написал код с использованием делегата? У меня не было информации о том, можно ли повторно использовать код обработки ошибок, поэтому я предположил, что это не так, и решил использовать делегата, поскольку я полагал, что людям будет легко перейти от этого к пониманию того, что это может быть `` правильный '' метод (как и у вас), тогда как если бы я показал использование «правильной» функции, люди могли бы не осознавать, что делегат был бы альтернативой.

2
ответ дан 30 November 2019 в 08:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: