Лямбда-синтаксис в C # 3 делает действительно удобным создание однострочных анонимных методов. Это определенное улучшение по сравнению с более простым анонимным синтаксисом делегатов, который дал нам C # 2. Однако удобство лямбд приводит к искушению использовать их в тех местах, где нам необязательно нужна семантика функционального программирования, которую они предоставляют.
Например, я часто нахожу, что мои обработчики событий (или, по крайней мере, начинаются как ) простые однострочные, которые устанавливают значение состояния, или вызывают другую функцию, или устанавливают свойство для другого объекта и т. д. Следует ли мне загромождать мой класс еще одной простой функцией или просто вставить лямбду в событие в моем конструкторе?
В этом сценарии есть несколько явных недостатков лямбды:
- Я не могу вызвать мой обработчик событий напрямую; это может быть вызвано только событием. Конечно, в случае этих простых обработчиков событий, вряд ли мне понадобится время для их непосредственного вызова .
- Я не могу отцепить моего обработчика от события. С другой стороны, мне редко нужно отсоединять обработчики событий, так что в любом случае это не большая проблема .
Эти две вещи меня не особо беспокоят по указанным причинам. И я мог бы решить обе эти проблемы, если бы они действительно были проблемами, храня лямбду в делегате-члене, но это отчасти помешало бы использовать лямбды для их удобства и содержать класс в чистоте беспорядка.
Однако есть еще две вещи, которые, я думаю, не столь очевидны, но, возможно, более проблематичны.
Каждая лямбда-функция формирует замыкание над своей содержащей областью. Это может означать, что временные объекты, созданные ранее в конструкторе, остаются живыми гораздо дольше, чем нужно из-за замыканий, поддерживающих ссылки на них. Теперь, надеюсь, компилятор достаточно умен, чтобы исключить объекты из замыкания, которые лямбда не использует, но я не уверен. Кто-нибудь знает?
К счастью, это не всегда проблема, так как я не часто создаю временные объекты в своих конструкторах. Я могу себе представить сценарий, где я это сделал, и где я не мог легко охватить его за пределами лямбды.
- Может пострадать ремонтопригодность. Долгое время. Если у меня есть некоторые обработчики событий, определенные как функции, а некоторые - как лямбды, я волнуюсь, что это может затруднить отслеживание ошибок или просто понимание класса. И позже, если и когда мои обработчики событий будут расширяться, мне придется либо переместить их в функции уровня класса, либо иметь дело с тем фактом, что мой конструктор теперь содержит значительный объем кода, который реализует функциональность моего класса .
Поэтому я хочу опираться на советы и опыт других, возможно, тех, кто имеет опыт работы на других языках с функциями функционального программирования. Существуют ли лучшие практики для такого рода вещей? Вы бы избежали использования лямбда-выражений в обработчиках событий или в других случаях, когда лямбда значительно выходит за рамки его охвата? Если нет, то при каком пороге вы решили бы использовать реальную функцию вместо лямбды? Кто-нибудь из перечисленных выше подводных камней значительно кого-нибудь укусил? Есть ли подводные камни, о которых я не думал?