Подтвердить что ты не робот

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

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

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
}

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

4b9b3361

Ответ 1

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

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

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

Недостатки использования выражения лямбда вместо частного метода:

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

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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!");
}

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

Ответ 5

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

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

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

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