DWScript:如何从Delphi端读取元类参数

时间:2014-04-15 13:08:06

标签: delphi dwscript

我在使用DWScript中的元类时遇到了问题。

我们正在使用脚本来启用VAR和最终用户来自定义我们的应用程序。

我们的应用程序数据基本上由树结构中的许多小对象组成。每个对象都可以是" dumb"因为它只是显示数据,或者它可以以某种方式智能化。通过将不同的脚本类与树对象相关联,使用脚本实现智能。

我遇到的问题是脚本需要与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?
修改:我在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);

1 个答案:

答案 0 :(得分:2)

除非我误解,否则您可能不应该查找最后一部分的符号表,而是在dwsUnitMyClassesFunctionsRegisterItemClassEval中维护一个已注册项目类的表。

背后的基本原理可能是用户可能有两个TMyItem'符号,在两个不同的上下文中,但只有一个注册。注册的是你想要的那个,我不认为有一种可靠的方法可以找出相关的符号(因为重要的上下文不会是你尝试的那个)将字符串解析回符号,但符号和字符串相关联的符号,即注册的位置)