delphi - 匿名方法的范围

标签 delphi scope delphi-2009 anonymous-methods

匿名方法的一个好处是我可以使用调用上下文中的本地变量。这对于输出参数和函数结果不起作用有什么原因吗?

function ReturnTwoStrings (out Str1 : String) : String;
begin
  ExecuteProcedure (procedure
                    begin
                      Str1 := 'First String';
                      Result := 'Second String';
                    end);
end;

当然是非常人为的例子,但我遇到了一些情况,这会很有用。

当我尝试编译它时,编译器提示他“无法捕获符号”。另外,当我尝试执行此操作时,我遇到了一次内部错误。

编辑我刚刚意识到它适用于正常参数,例如

... (List : TList)

这不是和其他情况一样有问题吗?谁保证每当执行匿名方法时引用仍然指向事件对象?

最佳答案

无法捕获Var和out参数以及Result变量,因为无法静态验证此操作的安全性。当 Result 变量是托管类型(例如字符串或接口(interface))时,存储实际上由调用者分配,并且对此存储的引用作为隐式参数传递;换句话说,Result 变量,根据其类型,就像一个输出参数。

由于乔恩提到的原因,无法验证安全性。由匿名方法创建的闭包可以比创建它的方法激活的生命周期长,并且同样可以比调用它创建的方法的方法的激活的生命周期长。因此,捕获的任何 var 或 out 参数或 Result 变量最终都可能成为孤立变量,并且将来从闭包内部对它们进行的任何写入都会破坏堆栈。

当然,Delphi 并不在托管环境中运行,并且它没有与例如相同的安全限制。 C#。该语言可以让你做你想做的事。然而,在出现问题的情况下,这会导致很难诊断错误。不良行为将表现为例程中的局部变量改变值,而没有明显的直接原因;如果从另一个线程调用方法引用,情况会更糟。

这将很难调试。即使硬件内存断点也是一个相对较差的工具,因为堆栈会被频繁修改。人们需要在命中另一个断点时(例如,在方法进入时)有条件地打开硬件内存断点。 Delphi 调试器可以做到这一点,但我大胆猜测大多数人不了解这项技术。

更新:关于对问题的补充,按值传递实例引用的语义在包含闭包的方法(并捕获 paramete0 和不包含闭包的方法)之间几乎没有什么不同闭包。任一方法都可以保留对按值传递的参数的引用;不捕获参数的方法可以简单地将引用添加到列表中,或将其存储在私有(private)字段中。

通过引用传递参数的情况有所不同,因为调用者的期望不同。程序员这样做:

procedure GetSomeString(out s: string);
// ...
GetSomeString(s);

如果 GetSomeString 保留对传入的 s 变量的引用,将会感到非常惊讶。另一方面:

procedure AddObject(obj: TObject);
// ...
AddObject(TObject.Create);

AddObject 保留引用并不奇怪,因为这个名称意味着它将参数添加到某个有状态存储中。有状态存储是否采用闭包的形式是 AddObject 方法的实现细节。

关于delphi - 匿名方法的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/801147/

相关文章:

delphi - 使用 Delphi 打开 ANSI 文件并保存 Unicode 文件

r - 嵌套最大化与在 R 中使用全局变量的需要并行

java - JButton变量无法解析

mysql - MySQL 5 中的 utf8 数据需要哪个 dbExpress ServerCharSet?

windows - 如何获取U盘的制造商序列号?

Delphi计算WGS84 2点的交集

delphi - 动态创建的 FireMonkey TPopupMenu 不弹出

web-services - 如何在delphi SOAP服务器中获取客户端mac地址?

PHP,变量范围问题

Delphi - ListView问题