4

DWScript スクリプトから、Delphi 側で公開されているオブジェクト インスタンスのメソッドを呼び出します。このメソッドは、とりわけ、列挙されたデータ型のセットである引数を取ります。この列挙型データ型は、Delphi からスクリプトに公開されます。

スクリプトのコンパイル時に生成されるエラー メッセージから、DWScript は整数の配列としてそのような引数を渡し、Delphi 側はバリアント (TData) の配列を受け取ることがわかりました。

Delphi 側で、配列をループするラッパーを作成し、対応する一連の変数を再構築して実際の Delphi 関数に渡す必要がありました。配列へのアクセスは、「ProgramInfo.Vars['MsgFlags'].GetData」を使用して行われます。

これは完全にうまく機能しますが、これは正しいことでしょうか? 私は何か見落としてますか?

スクリプト側のコード:

procedure Test;
begin
    DelphiObject.Demo('Hello', [mffStop, mffClose]);
end;

Delphi サイド コード:

TFlag  = (mmfStop, mffStart, mmfClose);
TFlags = set of TFlag;

// Internal method doing the actual job
procedure TDelphiObject.DemoInternal(
    const MsgText  : String;
    const MsgFlags : TFlags);
begin
    // Some code...
end;

// Wrapper method exposed to script
procedure TDelphiObject.Demo(
    const MsgText : String;
    const MsgFlags : array of integer);
var
    Flags      : TFlags;
    I          : Integer;
begin
    Flags := [];
    for I := Low(MsgFlags) to High(MsgFlags) do
        Flags := Flags + [TFlag(MsgFlags[I])];
    DemoInternal(MsgText, Flags);
end;
4

1 に答える 1

3

私は Delphi 側を少し違った方法で実装しますが (以下を参照)、それを除けば、あなたのソリューションは正しいように見えます。


お気づきのように、奇妙な点は、DWScript が静的セットを配列として表すことです。ただし、これはコンパイラ フロントエンドの単なる制限であり、いつか解決されることを願っています。DWScript の問題 #10: 静的配列からセットへの暗黙的なキャストを改善する を参照してください。

次のスクリプトは、コンパイラがセットと配列の間で暗黙的なキャストを実行する場合を示しています。

type
  TMyEnum = (meOne, meTwo);
type
  TMySet = set of TMyEnum;
type
  TMyArray = array of TMyEnum;

procedure TestSet(MySet: TMySet);
begin
  ShowMessage(integer(MySet).toString);
end;

procedure TestArray(MyArray: TMyArray);
var
  MySet: TMySet;
begin
  MySet := [];
  for var i := 0 to MyArray.Length-1 do
    Include(MySet, MyArray[i]);
  ShowMessage(integer(MySet).toString);
end;

begin
  TestSet([]);
  TestArray([]);
  TestSet([meOne]);
  TestArray([meOne]);
  TestSet([meOne, meTwo]);
  TestArray([meOne, meTwo]);

  var VarSet: TMySet = [meOne, meTwo];
  TestSet(VarSet);
  // Syntax Error: Argument 0 expects type "array of TMyEnum" instead of "TMySet"
  // TestArray(VarSet);

  var VarArray: TMyArray = [meOne, meTwo];
  TestArray(VarArray);
  // Syntax Error: Argument 0 expects type "array of TMyEnum" instead of "TMySet"
  // TestArray(VarSet);

  // Syntax Error: Incompatible types: "TMySet" and "array [0..1] of TMyEnum"  const ConstSet: TMySet = [meOne, meTwo];
  // const ConstSet: TMySet = [meOne, meTwo];
  // TestSet(ConstSet);
  // TestArray(ConstSet);

  // Syntax Error: Incompatible types: "array of TMyEnum" and "array [0..1] of TMyEnum"
  // const ConstArray: TMyArray = [meOne, meTwo];
  // TestSet(ConstArray);
  // TestArray(ConstArray);
end;

上記は純粋にスクリプト側の実装です。Delphi 側の実装をミックスに追加すると、問題が発生する可能性があります。

MessageDlg関数の単純化された実装を検討してください。

Delphi 側の宣言 (TdwsUnit 経由):

type
  TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, etc...);
  TMsgDlgButtons = set of TMsgDlgBtn;

function MessageDlg(const Msg: string; Buttons: TMsgDlgButtons): integer;

Delphi 側の実装:

Info.ResultAsInteger := MessageDlg(Info.ParamAsString[0], mtInformation, TMsgDlgButtons(Word(Info.ParamAsInteger[1])), -1);

スクリプト側の使用法:

begin
  // Implicit cast from array to set fails:
  // Syntax Error: There is no overloaded version of "MessageDlg" that can be called with these arguments
  // MessageDlg('Test', [mbOK]);

  var Buttons: TMsgDlgButtons = [mbOK];
  MessageDlg('Test', Buttons);
end;

代わりに、セットパラメーターを配列として宣言するソリューションで同じことを試してみましょう。

Delphi 側の宣言 (TdwsUnit 経由):

type
  TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, etc...);
  TMsgDlgButtons = array of TMsgDlgBtn;

function MessageDlg(const Msg: string; Buttons: TMsgDlgButtons): integer;

Delphi 側の実装:

var
  Buttons: TMsgDlgButtons;
  i: integer;
  ButtonArray: IScriptDynArray;
begin
  ButtonArray := Info.Params[1].ScriptDynArray;
  Buttons := [];
  for i := 0 to ButtonArray.ArrayLength-1 do
    Include(Buttons, TMsgDlgBtn(ButtonArray.AsInteger[i]));
  Info.ResultAsInteger := MessageDlgEx(Info.ParamAsString[0], mtInformation, Buttons, -1);
end;

スクリプト側の使用法:

begin
  MessageDlg('Test', [mbOK]);

  var Buttons: TMsgDlgButtons = [mbOK];
  // Note that an implicit cast from set to array is performed
  MessageDlg('Test', Buttons);
end;

DWScriptの私自身のブランチでは、列挙値の配列からセットへの暗黙的なキャストを実行するようにコンパイラを変更しました。これは見事に機能し、他の方法では失敗する上記のすべてのケースを解決します。

于 2015-10-23T15:59:04.067 に答える