delphi - E2555 无法捕获符号 'Self'

标签 delphi anonymous-methods

当我运行以下代码时,我得到E2555 Cannot capture symbol 'Self'

type
  TLookupTable = record
    FData: TArray<TOtherRec>;
    procedure ReverseLeftToRight;
  end;

procedure TLookupTable.ReverseLeftToRight;
begin
  Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
    FData[i]:= FData[i].ReverseLeftRight;
  end); {for i}
end;

我该如何解决这个问题?

最佳答案

问题在于 var 参数(包括 Self 的隐藏 var 参数)不会被捕获。但是,我们不想复制记录,那是没有用的,因为那样我们的方法就不起作用。

诀窍是使隐藏的 self 参数显式化。
如果它是一个类,那么很简单(var S:= Self),如果不是,则必须声明一个指向记录的指针。

procedure TLookupTable.ReverseLeftToRight;
type 
  PLookupTable = ^TLookupTable;
var
  S: PLookupTable;
begin
  S:= @Self;
  Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
    S.FData[i]:= S.FData[i].ReverseLeftRight;
  end); {for i}
end;

现在编译器不再提示。
(请注意,我使用的是 S^.xyz 的隐式语法)。

德尔福里约
使用如下所示的内联 var 声明是行不通的。

  //S: PLookupTable;
begin
  var S:= @Self; //inline declaration
  Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
    S.FData[i]:= S.FData[i].ReverseLeftRight;
  end); {for i}

这会生成:E2018 需要记录、对象或类类型
我猜内联 @Self 被解析为通用指针,这很遗憾,因为有足够的信息来推断内联变量的正确类型。

异步问题
如果您使用异步 (.NoWait) 线程/任务执行代码,那么最好将 FData 放入局部变量中。 FData 作为一个动态数组,已经是一个指针(因此不会发生复制,只是一个引用计数)。并且动态数组没有 Copy-on-Write 语义,因此原始数组将被更新。
事实上,在代码运行时,Self 记录可能会超出范围,因为指针操作 S:= @Self 不会导致 FData 上的引用计数增加)。这可能会导致访问冲突(或更严重)。
引用 FData 会导致其引用计数增加,这意味着它不能过早超出范围。

关于delphi - E2555 无法捕获符号 'Self',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54145783/

相关文章:

database - 如何正确访问在后台线程中创建的查询结果?

c# - 循环中匿名方法的不同 "execution context"的问题

c# - 为什么 is 或 as 运算符的左侧不允许使用 lambda 和匿名方法?

c# - 自调用匿名函数

delphi - XE7 FMX 损坏的 PNG 缩略图

delphi - 你能找到一个使用RTTI的实际应用程序TStringList吗

delphi - 在 Delphi 中,为什么传递接口(interface)变量有时需要它是 const 参数?

Delphi:模仿 MS OneNote 的数据结构

function - 如何将另一个函数返回的函数分配给函数变量?结果而不是生成函数本身

c# - 如何确定c#中的匿名函数参数?