如何使用 OmniThreadLibrary 中的 SetParameter 将数组作为参数传递给任务?
How to pass an array as parameter to a task with SetParameter from OmniThreadLibrary?
在 Delphi XE8 中,我试图从 OmniThreadLibrary 将数组传递给 SetParameter
中的 OTL 任务:
implementation
type
TCookie = record
Name: string;
Value: string;
ExpDate: string;
ModDate: string;
end;
TCookieArray = array of TCookie;
var
CurCookies: TCookieArray;
procedure TForm1.btnStartTaskClick(Sender: TObject);
begin
SetLength(CurCookies, 2);
CurCookies[0].Name := 'username';
CurCookies[0].Value := 'Paul';
CurCookies[1].Name := 'password';
CurCookies[1].Value := 'none';
FGetCookieDetailsTask := CreateTask(GetCookieEntries, 'GetCookieEntries')
.MonitorWith(OTLMonitor)
// Compiler complaint:
.SetParameter('CookiesArray', TOmniValue.FromArray<TCookieArray>(CurCookies))
.Run;
end;
编译器抱怨 SetParameter 行:
[dcc32 Error] Unit1.pas(310): E2010 Incompatible types:
'System.TArray<Unit1.TCookieArray>' and 'TCookieArray'
不幸的是,OTL书中没有关于如何在SetParameter
中使用FromArray
将数组传递给任务的示例。
那么如何做到这一点?
编辑:ba__friend 要求我在他的回答的评论中显示我的解决方案的源代码:
FGetCookieDetailsTask := CreateTask(GetCookieEntries, 'GetCookieEntries')
.MonitorWith(OTLMonitor)
// Now no compiler complaint:
.SetParameter('CookiesArray', CurCookies)
.Run;
procedure GetCookieEntries(const task: IOmniTask);
var
TaskCookies, HostCookies: TCookieArray;
begin
HostCookies := task.Param['CookiesArray'];
TaskCookies := Copy(HostCookies, 0, Length(HostCookies));
你的代码有两个问题。
1) TCookieArray
必须声明为
TCookieArray = TArray<TCookie>;
从编译器的角度来看,array of T
和 TArray<T>
(很遗憾)不是一回事。
2) FromArray<T>
期望类型 T
是数组项类型,而不是数组类型(参见 OtlCommon),因此您必须将其从
TOmniValue.FromArray<TCookieArray>
至
TOmniValue.FromArray<TCookie>
要从任务访问此数组,请调用:
var
cookies: TCookieArray;
cookies := task.Param['CookiesArray'].ToArray<TCookie>;
旁注:这就是应该的工作方式。然而,在直到(包括)3.04b 的 OTL 中,记录类型在 ToArray<T>
和 FromArray<T>
中没有得到正确处理。 GitHub.
刚刚提交了一个修复程序
如果您想手动修复副本,需要进行两次修改。
在TOmniValue.CastFrom<T>
,这个街区
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
应该改为
if ds = 0 then // complicated stuff
if ti^.Kind = tkRecord then
Result.SetAsRecord(CreateAutoDestroyObject(
TOmniRecordWrapper<T>.Create(value)))
else
{$IFDEF OTL_ERTTI}
在 TOmniValue.CastTo<T>
之后的区块
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
应该改为
if ds = 0 then // complicated stuff
if ti.Kind = tkRecord then
Result := TOmniRecordWrapper<T>(CastToRecord.Value).Value
else
{$IFDEF OTL_ERTTI}
在 Delphi XE8 中,我试图从 OmniThreadLibrary 将数组传递给 SetParameter
中的 OTL 任务:
implementation
type
TCookie = record
Name: string;
Value: string;
ExpDate: string;
ModDate: string;
end;
TCookieArray = array of TCookie;
var
CurCookies: TCookieArray;
procedure TForm1.btnStartTaskClick(Sender: TObject);
begin
SetLength(CurCookies, 2);
CurCookies[0].Name := 'username';
CurCookies[0].Value := 'Paul';
CurCookies[1].Name := 'password';
CurCookies[1].Value := 'none';
FGetCookieDetailsTask := CreateTask(GetCookieEntries, 'GetCookieEntries')
.MonitorWith(OTLMonitor)
// Compiler complaint:
.SetParameter('CookiesArray', TOmniValue.FromArray<TCookieArray>(CurCookies))
.Run;
end;
编译器抱怨 SetParameter 行:
[dcc32 Error] Unit1.pas(310): E2010 Incompatible types:
'System.TArray<Unit1.TCookieArray>' and 'TCookieArray'
不幸的是,OTL书中没有关于如何在SetParameter
中使用FromArray
将数组传递给任务的示例。
那么如何做到这一点?
编辑:ba__friend 要求我在他的回答的评论中显示我的解决方案的源代码:
FGetCookieDetailsTask := CreateTask(GetCookieEntries, 'GetCookieEntries')
.MonitorWith(OTLMonitor)
// Now no compiler complaint:
.SetParameter('CookiesArray', CurCookies)
.Run;
procedure GetCookieEntries(const task: IOmniTask);
var
TaskCookies, HostCookies: TCookieArray;
begin
HostCookies := task.Param['CookiesArray'];
TaskCookies := Copy(HostCookies, 0, Length(HostCookies));
你的代码有两个问题。
1) TCookieArray
必须声明为
TCookieArray = TArray<TCookie>;
从编译器的角度来看,array of T
和 TArray<T>
(很遗憾)不是一回事。
2) FromArray<T>
期望类型 T
是数组项类型,而不是数组类型(参见 OtlCommon),因此您必须将其从
TOmniValue.FromArray<TCookieArray>
至
TOmniValue.FromArray<TCookie>
要从任务访问此数组,请调用:
var
cookies: TCookieArray;
cookies := task.Param['CookiesArray'].ToArray<TCookie>;
旁注:这就是应该的工作方式。然而,在直到(包括)3.04b 的 OTL 中,记录类型在 ToArray<T>
和 FromArray<T>
中没有得到正确处理。 GitHub.
如果您想手动修复副本,需要进行两次修改。
在TOmniValue.CastFrom<T>
,这个街区
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
应该改为
if ds = 0 then // complicated stuff
if ti^.Kind = tkRecord then
Result.SetAsRecord(CreateAutoDestroyObject(
TOmniRecordWrapper<T>.Create(value)))
else
{$IFDEF OTL_ERTTI}
在 TOmniValue.CastTo<T>
之后的区块
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
应该改为
if ds = 0 then // complicated stuff
if ti.Kind = tkRecord then
Result := TOmniRecordWrapper<T>(CastToRecord.Value).Value
else
{$IFDEF OTL_ERTTI}