【发布时间】:2014-04-15 13:08:05
【问题描述】:
我在 DWScript 中使用元类时遇到问题。
我们正在使用脚本来支持 VAR 和最终用户自定义我们的应用程序。
我们的应用程序数据基本上由树形结构中的许多小对象组成。每个对象都可以是“愚蠢的”,因为它只是显示数据,也可以以某种方式是智能的。智能是通过将不同的脚本类与树对象相关联的脚本来实现的。
我遇到的问题是脚本需要与 Delphi 端框架通信它应该使用什么脚本类来实现对象。基本上我需要将一个脚本元类传递给 Delphi 端,并将信息以一种可以安全保存的格式存储在那里(按类型名称,可能是一个字符串)。我还需要能够走另一条路; IE。将元类从 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;
德尔福实现
元类的声明,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);
【问题讨论】: