首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在DWScript中公开动态记录数组?

如何在DWScript中公开动态记录数组?
EN

Stack Overflow用户
提问于 2019-06-17 13:30:48
回答 1查看 358关注 0票数 1

我在DWScript单元中声明了一个简单的记录类型:

代码语言:javascript
复制
TSampleRecord = record
  name: string;
end;

如何将这样的数组从Delphi应用程序公开到脚本?例如,Delphi应用程序中的以下方法:

代码语言:javascript
复制
// Delphi side
function GetSampleRecordArray(): array of TSampleRecord;

必须可以从脚本访问:

代码语言:javascript
复制
// Script side
var myArray: array of TSampleRecord;
myArray := GetSampleRecordArray();
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-27 11:04:32

在脚本中注册返回动态记录数组的函数之前,您需要:

  1. 寄存器记录类型
  2. 注册该类型的动态数组

TdwsUnit有帮助器方法ExposeRTTIDynamicArray来公开用于脚本的动态数组。该方法是由单元TdwsRTTIExposer中的助手类dwsRTTIExposer介绍的。不幸的是,这只适用于一些基本类型的动态数组,而不是记录或对象。下面是一个简单的类,它帮助您在TdwsUnit实例的生存期内注册记录类型和动态数组:

代码语言:javascript
复制
uses
  System.SysUtils, System.Classes, System.Rtti, dwsComp, dwsExprs, dwsInfo,
  dwsErrors, dwsRTTIExposer;

type
  TDwsDynamicArrayExposer<T: record> = class(TComponent)
  strict private
    FRttiType: TRttiType;
    FDwsSymbol: TdwsSymbol;
    FDwsArray: TdwsArray;
    function GetDwsUnit: TdwsUnit;
  strict protected
    class var RTTIContext: TRttiContext;
    property DwsUnit: TdwsUnit read GetDwsUnit;
    property RttiType: TRttiType read FRttiType;
    property DwsSymbol: TdwsSymbol read FDwsSymbol;
    property DwsArray: TdwsArray read FDwsArray;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetInfo(const Info: IInfo; const Values: TArray<T>);
  end;

constructor TdwsDynamicArrayExposer<T>.Create(AOwner: TComponent);
begin
  if not (AOwner is TdwsUnit) then
    raise EArgumentException.Create('Owner must be instance of TdwsUnit.');
  inherited;
  FRttiType := RTTIContext.GetType(TypeInfo(T));
  FDwsSymbol := DwsUnit.ExposeRTTI(FRttiType.Handle);
  FDwsArray := DwsUnit.Arrays.Add;
  FDwsArray.DataType := FDwsSymbol.Name;
  FDwsArray.Name := FDwsSymbol.Name + 'Array';
  FDwsArray.IsDynamic := True;
end;

destructor TdwsDynamicArrayExposer<T>.Destroy;
begin
  if Assigned(DwsUnit) and (not (csDestroying in DwsUnit.ComponentState)) then
  begin
    // in case something went wrong in constructor
    FDwsArray.Free;
    FDwsSymbol.Free;
  end;
  inherited;
end;

function TdwsDynamicArrayExposer<T>.GetDwsUnit: TdwsUnit;
begin
  Result := TdwsUnit(Owner);
end;

procedure TdwsDynamicArrayExposer<T>.SetInfo(const Info: IInfo; const Values: TArray<T>);
var
  Index: Integer;
begin
  Info.Member['Length'].ValueAsInteger := Length(Values);
  for Index := 0 to Length(Values) - 1 do
    TdwsRTTIInvoker.AssignRecordFromValue(Info.Element([Index]),
      TValue.From<T>(Values[Index]), RttiType);
end;

该类还为初始化SetInfo实例提供了方便的方法(参数、变量、结果变量、.)从一个动态数组。

现在,您可以为您的TSampleRecord定义专门的说明程序,并在DWS单元中注册函数GetSampleRecordArray

代码语言:javascript
复制
type
  TSampleRecord = record
    Name: string;
  end;

  TArrayOfSampleRecordExposer = class(TdwsDynamicArrayExposer<TSampleRecord>)
  strict private
    FGetSampleRecordArrayFunction: TdwsFunction;
    procedure OnGetSampleRecordArrayEval(Info: TProgramInfo);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

function GetSampleRecordArray: TArray<TSampleRecord>;
begin
  SetLength(Result, 3);
  Result[0].Name := 'Name 0';
  Result[1].Name := 'Name 1';
  Result[2].Name := 'Name 2';
end;

constructor TArrayOfSampleRecordExposer.Create(AOwner: TComponent);
begin
  inherited;
  FGetSampleRecordArrayFunction := DwsUnit.Functions.Add;
  FGetSampleRecordArrayFunction.Name := 'GetSampleRecordArray';
  FGetSampleRecordArrayFunction.ResultType := DwsArray.Name;
  FGetSampleRecordArrayFunction.OnEval := OnGetSampleRecordArrayEval;
end;

destructor TArrayOfSampleRecordExposer.Destroy;
begin
  if Assigned(DwsUnit) and (not (csDestroying in DwsUnit.ComponentState)) then
    FGetSampleRecordArrayFunction.Free;
  inherited;
end;

procedure TArrayOfSampleRecordExposer.OnGetSampleRecordArrayEval(Info: TProgramInfo);
begin
  SetInfo(Info.ResultVars, GetSampleRecordArray);
end;

最后,通过实例化TArrayOfSampleRecordExposer注册Delphi函数。

代码语言:javascript
复制
Dws := TDelphiWebScript.Create(nil);
DwsUnit := TdwsUnit.Create(Dws);
DwsUnit.UnitName := 'Unit1';
DwsUnit.Script := Dws;
// one-time registration
TArrayOfSampleRecordExposer.Create(DwsUnit);

// ...

DwsProgram := Dws.Compile(
  'var SampleRecords := GetSampleRecordArray;'#13#10 +
  'for var SampleRecord in SampleRecords do'#13#10 +
  '  Println(SampleRecord.Name);');
if DwsProgram.Msgs.Count > 0 then
  raise Exception.Create(DwsProgram.Msgs.AsInfo);
DwsProgramExecution := DwsProgram.Execute;

这将产生输出(DwsProgramExecution.Result.ToString):

名称0 名称1 名称2

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56632386

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档