【问题标题】:DWScript: How to read a meta class parameter from Delphi sideDWScript:如何从 Delphi 端读取元类参数
【发布时间】: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);

【问题讨论】:

    标签: delphi dwscript


    【解决方案1】:

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

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

    【讨论】:

    • 我明白你的意思。我本来希望符号查找使用正常的范围规则,因此以后任何同名类的声明都会覆盖前一个(当然前提是前一个仍在范围内)。我无法在单元上维护符号表,因为该单元可以在许多不同的独立脚本之间共享,但我可以简单地存储指向已存储类名的对象上的符号的指针。我有点担心这个符号可能会在我背后被删除,给我留下一个无效的参考。
    • [...continuing...]在创建 TMyItem 的实例时似乎还缺少一些东西。由于无法通过普通符号查找找到该符号,因此我无法使用通常的 Info.Vars['TMyItem'].GetConstructor。相反,我不得不调用受保护的TProgramInfo.GetSymbolInfo 来创建一个 IInfo 对象并在其上调用构造函数(这反过来又引导我到this bug)。
    • 由于正常的范围规则,您没有找到它,您尝试查找它的功能是用户类不在范围内的单元的一部分,因此您有回到程序的根表查看它。如果您想在程序级别拥有 IInfo,则可以将该根表传递给新的 TProgramInfo.Table 属性。至于列表,您可以拥有一个按执行的环境,您可以在其中存储自定义内容(参见 WebEnvironement 示例)
    • 我正在尝试从我声明它的同一脚本中解析符号,所以我希望它在范围内。如果我制作一个重现问题的小样本并将其作为错误提交,也许会更好?我不明白你的意思 wrt TProgramInfo.Table。我已经在使用自定义环境来为脚本提供上下文,但我认为在这种情况下这不是存储符号信息的正确位置。我是 AFK ATM,但我会在我回来时解释原因。
    • 我以为您试图从 TdwsUnit 中的函数解析? (如果是这样,您的代码在 TdwsUnit 的上下文中,即它的实现位置,而不是调用该函数的单元)。无论如何,您可能想在 googlecode tracker 中提交带有详细信息的问题,这将比 cmets 更方便。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2015-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多