我在使用DWScript中的元类时遇到了问题。
我们正在使用脚本来启用VAR和最终用户来自定义我们的应用程序。
我们的应用程序数据基本上由树结构中的许多小对象组成。每个对象都可以是" dumb"因为它只是显示数据,或者它可以以某种方式智能化。通过将不同的脚本类与树对象相关联,使用脚本实现智能。
我遇到的问题是脚本需要与Delphi端框架进行通信,它应该使用哪个脚本类来实现该对象。基本上我需要将脚本元类传递给Delphi端,并以可以安全持久化的格式存储信息(通过类型名称,可能是字符串)。我还需要能够走另一条路;即将元类从Delphi端返回给脚本。
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;
元类的声明,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?
修改:我在old question找到了问题的一部分的答案
简而言之,解决方案是将参数值转换为TSymbol
:
现在假设我将类名存储为字符串。如何从此类名称返回符号?我需要这个,因为正如脚本可以设置项目类(使用上面的代码),脚本也可以要求一个项目'类。
我尝试使用似乎的四种不同方法中的任何一种来查找符号表,以便做我需要的但是没有一种能找到符号。
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?
编辑:我现在找到了最后一部分的可能解决方案。
以下似乎有效,但我不确定这是否是正确的方法。我原以为我需要将符号搜索的范围限制在当前的脚本单元中。
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);
答案 0 :(得分:2)
除非我误解,否则您可能不应该查找最后一部分的符号表,而是在dwsUnitMyClassesFunctionsRegisterItemClassEval中维护一个已注册项目类的表。
背后的基本原理可能是用户可能有两个TMyItem'符号,在两个不同的上下文中,但只有一个注册。注册的是你想要的那个,我不认为有一种可靠的方法可以找出相关的符号(因为重要的上下文不会是你尝试的那个)将字符串解析回符号,但符号和字符串相关联的符号,即注册的位置)