C# 3 中的 Lambda 语法使得创建单行匿名方法非常方便。相比 C# 2 中更加冗长的匿名委托语法,它们无疑是一种进步。然而,Lambda 的便利性也带来了一个诱惑:在不需要提供函数式编程语义的地方使用它们。
例如,我经常发现我的事件处理程序(或者至少起初)是简单的单行代码,用于设置状态值、调用另一个函数或设置另一个对象的属性等。对于这些情况,我应该在类中添加另一个简单函数,还是将 Lambda 填充到构造函数中的事件中呢?
在这种情况下,Lambda 有一些明显的缺点:
- 我不能直接调用事件处理程序;它只能由事件触发。当然,在这些简单的事件处理程序中,几乎没有必要直接调用它们。 - 我不能从事件中解除挂钩处理程序。另一方面,我很少需要取消挂钩事件处理程序,所以这不是什么问题。
这两个问题并不让我太困扰,因为已经有了解决办法。如果真的有问题,我可以通过将 Lambda 存储在成员委托中来解决这两个问题,但那样做会失去使用 Lambda 的便利和保持类中不杂乱的目的。
然而,还有两个问题可能不太明显,但可能更加棘手:
- 每个 Lambda 函数都形成其所在作用域的闭包。这可能意味着由于闭包维护对它们的引用,构造函数中早期创建的临时对象会比需要更长时间地存活。幸运的是,编译器应该足够聪明,可以将 Lambda 不使用的对象排除在闭包之外,但我不确定。有人知道吗? - 可能会影响可维护性。如果我将一些事件处理程序定义为函数,另一些定义为 Lambda,那么跟踪错误或理解类可能会更加困难。而且,如果我的事件处理程序最终扩展,我要么必须将它们移动到类级别的函数中,要么就必须接受构造函数现在包含实现类功能的相当数量的代码这一事实。
例如,我经常发现我的事件处理程序(或者至少起初)是简单的单行代码,用于设置状态值、调用另一个函数或设置另一个对象的属性等。对于这些情况,我应该在类中添加另一个简单函数,还是将 Lambda 填充到构造函数中的事件中呢?
在这种情况下,Lambda 有一些明显的缺点:
- 我不能直接调用事件处理程序;它只能由事件触发。当然,在这些简单的事件处理程序中,几乎没有必要直接调用它们。 - 我不能从事件中解除挂钩处理程序。另一方面,我很少需要取消挂钩事件处理程序,所以这不是什么问题。
这两个问题并不让我太困扰,因为已经有了解决办法。如果真的有问题,我可以通过将 Lambda 存储在成员委托中来解决这两个问题,但那样做会失去使用 Lambda 的便利和保持类中不杂乱的目的。
然而,还有两个问题可能不太明显,但可能更加棘手:
- 每个 Lambda 函数都形成其所在作用域的闭包。这可能意味着由于闭包维护对它们的引用,构造函数中早期创建的临时对象会比需要更长时间地存活。幸运的是,编译器应该足够聪明,可以将 Lambda 不使用的对象排除在闭包之外,但我不确定。有人知道吗? - 可能会影响可维护性。如果我将一些事件处理程序定义为函数,另一些定义为 Lambda,那么跟踪错误或理解类可能会更加困难。而且,如果我的事件处理程序最终扩展,我要么必须将它们移动到类级别的函数中,要么就必须接受构造函数现在包含实现类功能的相当数量的代码这一事实。
我希望能借鉴其他有函数式编程特点语言经验的人的建议和经验。这种情况下是否有已经确立的最佳实践?在事件处理程序或其他情况下,您会避免使用lambda表达式吗?如果不是,那么在什么阈值下您会决定使用真正的函数而不是lambda表达式?上述任何陷阱是否曾经显著影响过任何人?还有我没有想到的陷阱吗?