In Delphi XE8, I am trying to pass an array to the OTL task in SetParameter
from OmniThreadLibrary:
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;
The compiler complains about the SetParameter line:
[dcc32 Error] Unit1.pas(310): E2010 Incompatible types:
'System.TArray<Unit1.TCookieArray>' and 'TCookieArray'
Unfortunately, there are no examples in the OTL book on how to use FromArray
in SetParameter
to pass an array to the task.
So how can this be done?
EDIT: ba__friend asked that I show the source code from my solution in the comments of his answer:
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));
There are two problems in your code.
1) TCookieArray
has to be declared as
TCookieArray = TArray<TCookie>;
From the compiler's standpoint, array of T
and TArray<T>
are (sadly) not the same thing.
2) FromArray<T>
expects the type T
to be the array item type, not the array type (see OtlCommon), so you have to change it from
TOmniValue.FromArray<TCookieArray>
to
TOmniValue.FromArray<TCookie>
To access this array from a task, call:
var
cookies: TCookieArray;
cookies := task.Param['CookiesArray'].ToArray<TCookie>;
Side note: This is how things should work. In OTL up to (and including) 3.04b, record type is, however, not handled correctly in ToArray<T>
and FromArray<T>
. A fix for that has just been committed to the GitHub.
If you want to fix your copy manually, two modifications are needed.
In TOmniValue.CastFrom<T>
, this block
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
should be changed to
if ds = 0 then // complicated stuff
if ti^.Kind = tkRecord then
Result.SetAsRecord(CreateAutoDestroyObject(
TOmniRecordWrapper<T>.Create(value)))
else
{$IFDEF OTL_ERTTI}
In TOmniValue.CastTo<T>
, following block
if ds = 0 then // complicated stuff
{$IFDEF OTL_ERTTI}
should be changed to
if ds = 0 then // complicated stuff
if ti.Kind = tkRecord then
Result := TOmniRecordWrapper<T>(CastToRecord.Value).Value
else
{$IFDEF OTL_ERTTI}