3

DWScript でのメタ クラスの使用に問題があります。

スクリプトを使用して、VAR とエンド ユーザーがアプリケーションをカスタマイズできるようにしています。

私たちのアプリケーション データは、基本的にツリー構造の小さなオブジェクトで構成されています。各オブジェクトは、データを表示するだけの「ダム」であるか、または何らかの方法でインテリジェントである可能性があります。インテリジェンスは、さまざまなスクリプト クラスをツリ​​ー オブジェクトに関連付けることにより、スクリプトで実装されます。

私が抱えている問題は、オブジェクトを実装するためにどのスクリプト クラスを使用する必要があるかを、スクリプトが Delphi サイド フレームワークに伝える必要があることです。基本的には、スクリプト メタ クラスを Delphi 側に渡し、そこに情報を安全に永続化できる形式で保存する必要があります (型名で、おそらく文字列として)。また、逆方向に移動できるようにする必要があります。つまり、メタ クラスを Delphi 側からスクリプトに返します。

TdwsUnit 宣言

type
  // Base class of all tree objects
  TItem = class
    ...
  end;


  // The meta class
  // This is actually declared in code since TdwsUnit doesn't have design time support for meta classes.
  // Shown here for readability.
  TItemClass = class of TItem;


// The procedure that passes the meta class to the Delphi side.
// I cannot use a TItemClass parameter as that isn't declared until run time (after the TdwsUnit has initialized its tables).
procedure RegisterItemClass(AClass: TClass);

スクリプト

type
  TMyItem = class(TItem)
    ...
  end;

begin
  // Pass the meta class to the Delphi side.
  // The Delphi side will use this to create a script object of the specified type
  // and attach it to the Delphi side object.

  RegisterItemClass(TMyItem);
end;

Delphi の実装

メタクラスの宣言、TItemClass. で完了TdwsUnit.OnAfterInitUnitTable

procedure TMyDataModule.dwsUnitMyClassesAfterInitUnitTable(Sender: TObject);
var
  ItemClass: TClassSymbol;
  MetaClass: TClassOfSymbol;
begin
  // Find the base class symbol
  ItemClass := dwsUnitMyClasses.Table.FindTypeLocal('TItem') as TClassSymbol;
  // Create a meta class symbol
  MetaClass := TClassOfSymbol.Create('TItemClass', ItemClass);
  dwsUnitMyClasses.Table.AddSymbol(MetaClass);
end;

RegisterItemClass実装

procedure TMyDataModule.dwsUnitMyClassesFunctionsRegisterItemClassEval(info: TProgramInfo);
var
  ItemClassSymbol: TSymbol;
  ItemClassName: string;
begin
  ItemClassSymbol := TSymbol(Info.Params[0].ValueAsInteger);
  ItemClassName := ItemClassSymbol.Name;
  ...
end;

問題は、メタ クラス パラメータから TSymbol を取得する方法です。
編集:この古い質問で、問題の一部に対する答えを見つけました。
要するに、解決策は、パラメーター値を a にキャストすることですTSymbol

でも...

クラス名を文字列として保存するとします。このクラス名からシンボルに戻すにはどうすればよいですか? これが必要な理由は、スクリプトが (上記のコードを使用して) アイテム クラスを設定できるのと同様に、スクリプトがアイテムのクラスを要求することもできるからです。

必要なことを行うと思われる4つの異なる方法のいずれかを使用してシンボルテーブルを調べてみましたが、いずれもシンボルを見つけることができません。

var
  ItemClassName: string;
  ItemClassSymbol: TSymbol;
...
  ItemClassName := 'TMyItem';
...
  ItemClassSymbol := Info.Table.FindTypeSymbol(ItemClassName, cvMagic);
  if (ItemClassSymbol = nil) then
    ItemClassSymbol := Info.Table.FindSymbol(ItemClassName, cvMagic);
  if (ItemClassSymbol = nil) then
    ItemClassSymbol := Info.Table.FindTypeLocal(ItemClassName);
  if (ItemClassSymbol = nil) then
    ItemClassSymbol := Info.Table.FindLocal(ItemClassName);

  // ItemClassSymbol is nil at this point :-(

問題は、スクリプトで宣言されたメタ クラスの名前が与えられた場合、Delphi 側から対応する TSymbol を取得するにはどうすればよいかということです。

編集:最後の部分に対する1つの可能な解決策を見つけました。

以下はうまくいくようですが、それが正しい方法であるかどうかはわかりません。シンボル検索の範囲を現在のスクリプト ユニットに限定する必要があると考えたでしょう。

var
  ItemClassName: string;
  ItemClassSymbol: TSymbol;
...
  ItemClassName := 'TMyItem';
...
  ItemClassSymbol := Info.Execution.Prog.RootTable.FindSymbol(ItemClassName, cvMagic);
  if (ItemClassSymbol = nil) then
    raise EScriptException.CreateFmt('ItemClass not found: %s', [ItemClassName]);

  Info.ResultAsInteger := Int64(ItemClassSymbol);
4

1 に答える 1