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);