【问题标题】:How to access a variable by its name(string)?如何通过名称(字符串)访问变量?
【发布时间】:2011-07-18 08:38:00
【问题描述】:

我有一些全局字符串变量。

我必须创建可以传递的函数并将它们存储在某种结构中。 稍后我需要枚举它们并检查它们的值。

如何轻松实现?

(我想我需要某种反射,或者存储指针数组)。 无论如何,我们将不胜感激。

谢谢!

【问题讨论】:

  • Delphi 有RTTIJava.netReflection。在谈论 Delphi 时,您应该将其称为 RTTI,而不是 Reflection。
  • @Cosmin 为什么? RTTI 是一种反射形式。仅当您碰巧知道该首字母缩写词时,RTTI 才有意义。 OP 要求进行反思,并不关心它是受 RTTI 影响还是其他机制影响。
  • @David,因为有人可能是知道 RTTI 是什么但不知道反射是什么的 Delphinian。因为文档称它为 RTTI。因为谷歌对“Delphi 反射”的唯一有用结果是那些暗示你应该称之为“RTTI”的结果。
  • @Cosmin 如果人们知道什么是 RTTI 但不知道什么是反射,那么这些人需要开阔眼界。反射是一个通用术语,RTTI 是反射的具体实现。

标签: delphi rtti


【解决方案1】:

首先,您不能为此目的使用 Delphi 的 RTTI,因为 Delphi 7 的 RTTI 仅涵盖已发布的类成员。即使您使用的是 Delphi XE,仍然没有全局变量的 RTTI(因为 RTTI 与类型相关,而不是与“单位”相关联)。

唯一可行的解​​决方案是创建自己的变量注册表并使用名称和指向 var 本身的指针注册全局变量。

例子:

unit Test;

interface

var SomeGlobal: Integer;
    SomeOtherGlobal: string;

implementation
begin
  RegisterGlobal('SomeGlobal', SomeGlobal);
  RegisterGlobal('SomeOtherGlobal', SomeOtherGlobal);
end.

RegisterXXX 类型是否需要在某个地方定义,可能在自己的单元中,如下所示:

unit GlobalsRegistrar;

interface

procedure RegisterGlobal(const VarName: string; var V: Integer); overload;
procedure RegisterGlobal(const VarName: string; var V: String); overload;
// other RegisterXXX routines

procedure SetGlobal(const VarName: string; const Value: Integer); overload;
procedure SetGlobal(const VarName:string; const Value:string); overload;
// other SetGlobal variants

function GetGlobalInteger(const VarName: string): Integer;    
function GetGlobalString(const VarName:string): string;
// other GetGlobal variants

implementation

// ....

end.

【讨论】:

  • var 参数而不是指针将使调用者的界面更愉快
  • var 参数也允许重载。但这仅适用于RegisterXXXSetXXX,Getter 需要是普通函数。
  • 真可惜,这不是一件容易的事。是的,注册 favriable 的指针是一种选择,但如果我有几十个这样的变量,我将不得不以另一种方式完成我的任务。谢谢!
  • @John,考虑完全不使用全局变量,而是使用全局类的已发布属性(这样您就可以使用 RTTI)。或者根本不使用任何变量,使用 TOndrej 建议的名称-值对。
  • 我可能会这样做,但如果我已经拥有带有全局变量的文件,我不想搞砸并重建整个当前的“解决方案”
【解决方案2】:

你也可以有一个全局的TStringList 变量来保存name-value pairs 的列表。

【讨论】:

  • 这是 Delphi 7 的唯一简单解决方案,但它从来都不是一个好的解决方案:将内容存储为字符串只是为了使用 TString 的 key=value 查找效率低下。还可以选择使用 TStringList 仅作为索引并将实际值存储在单独的数组中。
  • @Cosmin 所以你基本上是在说当前的 TStringList 实现效率低下。我同意,但这仍然是一个简单的解决方案,对于一个小列表应该是可以接受的。如果性能成为问题,您可以使用来自IniFilesTHashedStringList 或类似的后代。
  • 还有将所有内容存储为字符串的问题,因为TStringList.Value[] 是一个字符串。这就是我推荐混合实现的原因,其中TStringList(或TStringHash)仅用于索引,基本类型的普通数组用于实际值存储。
  • 您可以将变量内容保存在 TStringList.Objects[] 中,存储一个指针、一个包含值的对象或一个(变体)记录。
【解决方案3】:

在 Delphi 7 上,我将遵循 Cosmin 的接口理念,而对于实现,我将使用基于 Julian Bucknall 的 Delphi 出色数据结构代码 ezDSL 的字典类型。

XE 等 Delphi 的后期版本不仅具有更高级的 RTTI,它们还包括一个非常棒的字典类型,使用泛型,因此字典可以包含您喜欢的任何类型。 esDSL 字典很容易使用,但由于它是基于指针的,它不像 delphi 泛型字典那样类型安全。

由于您需要在非常快的时间内查找字符串“变量名”(我们喜欢称之为 O(1)),因此您需要的是一个字符串到变量的字典。您可以将字符串用作键,将变量用作字典中的值,然后摆脱原始的全局变量,或者您可以尝试一些相当复杂的指向全局的指针逻辑,但我真的认为您会更好用一个简单的 <string,variant> 键值元组字典关闭。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-05
    • 2012-05-02
    • 1970-01-01
    • 2023-01-09
    • 2022-08-17
    • 2014-11-23
    • 1970-01-01
    • 2016-07-30
    相关资源
    最近更新 更多