delphi – 在OTL中使用时,如何通过匿名方法捕获变量?

delphi – 在OTL中使用时,如何通过匿名方法捕获变量?,第1张

概述我想做的事: 我在genric列表中有一些对象.我想以匿名方法捕获每个对象,并将此方法作为单独的OTL任务执行. 这是一个简化的例子: program Project51;{$APPTYPE CONSOLE}uses SysUtils, Generics.Collections, OtlTaskControl, OtlTask;type TProc = reference to 我想做的事:

我在genric列表中有一些对象.我想以匿名方法捕获每个对象,并将此方法作为单独的OTL任务执行.

这是一个简化的例子:

program Project51;{$APPTYPE CONSolE}uses  SysUtils,Generics.Collections,OtlTaskControl,OtlTask;type  TProc = reference to procedure;type  TMyObject = class(TObject)  public    ID: Integer;  constructor Create(AID: Integer);  end;constructor TMyObject.Create(AID: Integer);begin  ID := AID;end;var  Objects: TList<TMyObject>;  LObject: TMyObject;  MyProc: TProc;begin  Objects := TList<TMyObject>.Create;  Objects.Add(TMyObject.Create(1));  Objects.Add(TMyObject.Create(2));  Objects.Add(TMyObject.Create(3));  for LObject in Objects do  begin    //This seems to work    MyProc := procedure    begin      Writeln(Format('[SameThread] Object ID: %d',[LObject.ID]));    end;    MyProc;    //This doesn't work,sometimes it returns 4 lines in console!?    CreateTask(      procedure(const Task: IOmniTask)      begin        Writeln(Format('[Thread %d] Object ID: %d',[Task.UniqueID,LObject.ID]));      end    ).Unobserved.Run;  end;  Sleep(500); //Just wait a bit for tasks to finish  Readln;end.

这就是结果:

正如您所看到的,捕获似乎在主线程中正常工作.但是,我不知道是否已捕获指向对象的指针或仅捕获其ID字段?

当我尝试捕获对象并将匿名方法传递给CreateTask函数时,事情变得很奇怪.

首先,似乎只捕获了TMyObject的第三个实例.其次,我在控制台日志中有四条消息,尽管我在通用列表中只有三个对象.第二种行为是不一致的,有时我在控制台中有三条消息,有时候我有四条消息.

请解释上面提到的两个问题的原因,并提出一个消除问题的解决方案,并允许我将每个对象实例传递给单独的OTL任务. (我不想使用常规的TThread类.)

解决方法 The documentation describes what’s happening:

Note that variable capture captures variables—not values. If a variable’s value changes after being captured by constructing an anonymous method,the value of the variable the anonymous method captured changes too,because they are the same variable with the same storage.

在您的代码中,只有一个LObject变量,因此您构造的所有匿名方法都会引用它.随着循环的进展,LObject的值会发生变化.这些任务还没有机会开始运行,所以当它们最终运行时,循环终止并且LObject有它的最终值.形式上,循环后最终值未定义.

要捕获循环变量的值,请将任务的创建包装在单独的函数中:

function CreateItemTask(Obj: TMyObject): TOmniTaskDelegate;begin  Result := procedure(const Task: IOmniTask)            begin              Writeln(Format('[Thread %d] Object ID: %d',Obj.ID]));            end;end;

然后更改循环代码:

CreateTask(CreateItemTask(LObject)).Unobserved.Run;
总结

以上是内存溢出为你收集整理的delphi – 在OTL中使用时,如何通过匿名方法捕获变量?全部内容,希望文章能够帮你解决delphi – 在OTL中使用时,如何通过匿名方法捕获变量?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/1263669.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存