我认为这个问题需要非常主观的判断。我是一名老派的Delphi开发者,也倾向于同意你的看法。闭包不仅会带来某些风险(正如David H在评论中指出的那样),而且还会降低所有接受过经典Delphi培训的开发者的可读性。那么,为什么它们被添加到语言中呢?例如,在Delphi XE中,语法格式化功能和闭包无法很好地配合使用,这增加了我对闭包的不信任;在Delphi编译器中添加了多少东西,IDE还没有完全升级以支持它们?当您公开承认如果Delphi语言冻结在Delphi 7级别并且永远不再进行改进,您会感到满意时,您就知道自己是一个暴躁的老计时器。但是,Delphi是一种生动、强大、不断发展的语法。这是一件好事。在您发现老式曲折的代码占据上风时,请反复告诉自己这一点。试试看。
我可以想到至少十个匿名方法真正有意义的场景以及为什么应该使用它们的原因,尽管我之前表示我不信任它们。我只会指出我决定个人使用的两个场景以及我在使用它们时限制自己的范围:
1.在Generics.Collections中,容器类的排序方法接受一个匿名方法,以便您可以轻松地提供一个排序逻辑位而不必编写与该排序方法期望的相同签名匹配的常规(非匿名)函数。新的泛型语法与此风格紧密结合,虽然一开始看起来很陌生,但会让你变得更加方便。
2.TThread方法(如Synchronize)被重载,并且除了支持单个TThreadMethod作为参数
Thread.Synchronize(aClassMethodWithoutParameters)
外,我一直感到痛苦的是将参数传递给该synchronize方法。现在,您可以使用闭包(匿名方法)并传递参数。
我建议在编写匿名方法时遵循以下限制:
A.我有一个个人的经验法则,即每个函数只有一个闭包,如果超过一个,请将该代码片段重构为自己的方法。这使您的“方法”的圆形复杂性不会变得疯狂。
B.此外,在每个闭包内,我更喜欢仅有一个方法调用及其参数,如果我最终编写了大块的代码,则将其重写为方法。闭包是用于变量捕获,而不是任意编写无限扭曲的代码。
样例排序:
var
aContainer:TList<TPair<String, Integer>>;
begin
aContainer.Sort(
TMyComparer.Construct(
function (const L, R: TPair<String, Integer>): integer
begin
result := SysUtils.CompareStr(L.Key,R.Key);
end ) );
end;
更新:有一条评论指出了“语言丑化”,我认为这种丑化是指写法上的差异:
x.Sort(
TMyComparer.Construct(
function (const L, R: TPair<String, Integer>): integer
begin
result := SysUtils.CompareStr(L.Key,R.Key);
end ) );
与其使用我在此进行比较的下面这个假设的鸭子类型(或者我应该说是推断类型)语法:
x.Sort( lambda( [L,R], [ SysUtils.CompareStr(L.Key,R.Key) ] ) )
像Smalltalk和Python这样的其他语言可以更紧凑地编写lambda,因为它们是动态类型的。例如,需要将IComparer作为传递给容器中Sort()方法的类型,就是强类型语言中具有泛型的接口特性所导致的复杂性的一个示例,以实现类似排序的特征。我不认为有一种好的方法来做到这一点。个人而言,我讨厌在函数调用括号内看到procedure、begin和end关键字,但我不知道还有什么别的合理的做法。