Использование лямбда-выражения против частного метода - PullRequest
18 голосов
/ 20 августа 2010

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

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
}

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

Ответы [ 7 ]

13 голосов
/ 20 августа 2010

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

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

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

9 голосов
/ 20 августа 2010

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

3 голосов
/ 20 августа 2010

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

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

2 голосов
/ 20 августа 2010

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

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

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

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

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

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

1 голос
/ 26 августа 2010

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

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

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

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

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

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

1 голос
/ 20 августа 2010

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

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

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

0 голосов
/ 20 августа 2010

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

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

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