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

DWScript:如何从Delphi端读取元类参数,delphi,dwscript,Delphi,Dwscript,在DWScript中使用元类时遇到问题 我们正在使用脚本来支持VAR和最终用户定制我们的应用程序 我们的应用程序数据基本上由树结构中的许多小对象组成。每个对象可以是“哑”的,因为它只显示数据,也可以是智能的。通过将不同的脚本类与树对象关联,通过脚本实现智能 我遇到的问题是,脚本需要与Delphi端框架通信,它应该使用什么脚本类来实现对象。基本上,我需要将一个脚本元类传递到Delphi端,并以一种可以安全持久化的格式(按类型名,可能是字符串)存储信息。我还需要能够走另一条路;也就是说,从Delph

在DWScript中使用元类时遇到问题

我们正在使用脚本来支持VAR和最终用户定制我们的应用程序

我们的应用程序数据基本上由树结构中的许多小对象组成。每个对象可以是“哑”的,因为它只显示数据,也可以是智能的。通过将不同的脚本类与树对象关联,通过脚本实现智能

我遇到的问题是,脚本需要与Delphi端框架通信,它应该使用什么脚本类来实现对象。基本上,我需要将一个脚本元类传递到Delphi端,并以一种可以安全持久化的格式(按类型名,可能是字符串)存储信息。我还需要能够走另一条路;也就是说,从Delphi端将meta类返回到脚本

TdwsUnit声明 剧本 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?
编辑:我在这篇文章中找到了问题一部分的答案。
简而言之,解决方案是将参数值强制转换为
TSymbol

然而。。。 现在假设我将类名存储为字符串。如何从该类名返回到符号?我需要这样做是因为,正如脚本可以设置item类(使用上面的代码)一样,脚本也可以请求items的类

我试着用四种不同的方法中的任何一种查找符号表,它们似乎都能满足我的需要,但没有一种能找到符号

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

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


这背后的理由可能是,用户可以在两个不同的上下文中拥有两个“TMyItem”符号,但只能注册一个。注册的是您想要的,我不认为有可靠的方法来找出相关的符号(因为重要的上下文不是您试图将字符串解析回符号的上下文,而是与符号和字符串关联的上下文,即它的注册位置)

我明白您的意思。我本来希望符号查找使用正常的作用域规则,因此以后对同名类的任何声明都将覆盖前一个(当然前提是前一个仍在作用域中)。我无法在该单元上维护符号表,因为该单元可以在许多不同的独立脚本之间共享,但我可以简单地在已经存储类名的对象上存储指向该符号的指针。虽然我有点担心这个符号可能会在我背后被删除,给我留下一个无效的引用。[…继续…]在创建TMyItem实例时,似乎也缺少了一些东西。由于普通的符号查找无法找到该符号,因此我无法使用通常的
Info.Vars['TMyItem'].GetConstructor
。相反,我必须调用受保护的
TProgramInfo.GetSymbolInfo
来创建一个IInfo对象并调用该对象的构造函数(这反过来又会导致我)。由于正常的作用域规则,您找不到它,您试图查找它的函数是用户类不在作用域中的单元的一部分,因此,您必须返回程序的根表才能看到它。如果您想在程序级拥有IInfo,可以将该根表传递给新的TProgramInfo.table属性。至于列表,您可以有一个每执行一次的环境,在这里您可以存储自定义内容(请参见WebEnvironment的示例)。我正在尝试从声明符号的同一脚本解析该符号,因此我希望它在范围内。如果我制作一个复制问题的小样本并将其作为bug提交,也许会更好?我不明白你的意思,wrt
TProgramInfo.Table
。我已经在使用自定义环境为脚本提供上下文,但我认为在本例中,这不是存储符号信息的正确位置。我是AFK ATM,但我回来后会解释原因。我以为你是想从TdwsUnit中的函数解析?(如果是这样,您的代码是在TdwsUnit的上下文中,即它的实现位置,而不是调用函数的单元)。无论如何,你可能想在谷歌代码跟踪器中提交一个问题,并提供详细信息,这比评论更方便。
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 :-(
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);