如何使用OmniThreadLibrary中的SetParameter将数组作为参数传递给任务?

时间:2015-08-29 15:45:30

标签: arrays delphi delphi-xe8 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书中没有关于如何在FromArray中使用SetParameter将数组传递给任务的示例。

那怎么办呢?

编辑: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 个答案:

答案 0 :(得分:2)

您的代码中存在两个问题。

1)TCookieArray必须声明为

TCookieArray = TArray<TCookie>;

从编译器的角度来看,array of TTArray<T>(遗憾地)并不是一回事。

2)FromArray<T>期望类型T是数组项类型,而不是数组类型(请参阅OtlCommon),因此您必须从

更改它
TOmniValue.FromArray<TCookieArray>

TOmniValue.FromArray<TCookie>

要从任务访问此数组,请致电:

var
  cookies: TCookieArray;

cookies := task.Param['CookiesArray'].ToArray<TCookie>;

旁注:这就是应该工作的方式。但是,在OTL最高(包括)3.04b中,记录类型在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}