获取属于任意类型的单元名称(TRttiType)

发布于 2024-09-25 18:33:37 字数 1432 浏览 4 评论 0原文

我需要获取任何 TRttiType< 的单位(命名空间)名称/代码>

到目前为止,我已经尝试了以下方法。

1) 使用 PTypeData.UnitName,此解决方案有效,但仅当 TTypeKind 为 tkClass 时。

procedure ListAllUnits;
var
  ctx  : TRttiContext;
  lType: TRttiType;
  Units: TStrings;
begin
  Units:=TStringList.Create;
  try
    ctx := TRttiContext.Create;
    for lType in ctx.GetTypes do
     if lType.IsInstance then //only works for classes
      if Units.IndexOf(UTF8ToString(GetTypeData(lType.Handle).UnitName))<0 then
      Units.Add(UTF8ToString(GetTypeData(lType.Handle).UnitName));
  Writeln(Units.Text);
  finally
    Units.Free;
  end;
end;

2)解析QualifiedName属性,这个解决方案到目前为止工作正常,但我对此不太满意。

procedure ListAllUnits2;

  function GetUnitName(lType: TRttiType): string;
  begin
    Result := StringReplace(lType.QualifiedName, '.' + lType.Name, '',[rfReplaceAll])
  end;

var
  ctx: TRttiContext;
  lType: TRttiType;
  Units: TStrings;
begin
  Units := TStringList.Create;
  try
    ctx := TRttiContext.Create;
    for lType in ctx.GetTypes do
      if Units.IndexOf(GetUnitName(lType)) < 0 then
        Units.Add(GetUnitName(lType));
    Writeln(Units.Text);
  finally
    Units.Free;
  end;
end;

问题是,是否存在另一种可靠的方法来获取任何 TRttiType 的单位名称?

I need to get the name of the unit (namespace) of any TRttiType.

so far, I have tried the following.

1) using the PTypeData.UnitName, this solution works, but only when the TTypeKind is tkClass.

procedure ListAllUnits;
var
  ctx  : TRttiContext;
  lType: TRttiType;
  Units: TStrings;
begin
  Units:=TStringList.Create;
  try
    ctx := TRttiContext.Create;
    for lType in ctx.GetTypes do
     if lType.IsInstance then //only works for classes
      if Units.IndexOf(UTF8ToString(GetTypeData(lType.Handle).UnitName))<0 then
      Units.Add(UTF8ToString(GetTypeData(lType.Handle).UnitName));
  Writeln(Units.Text);
  finally
    Units.Free;
  end;
end;

2) Parsing the QualifiedName property, This solution works ok until now, but I'm not very happy with it.

procedure ListAllUnits2;

  function GetUnitName(lType: TRttiType): string;
  begin
    Result := StringReplace(lType.QualifiedName, '.' + lType.Name, '',[rfReplaceAll])
  end;

var
  ctx: TRttiContext;
  lType: TRttiType;
  Units: TStrings;
begin
  Units := TStringList.Create;
  try
    ctx := TRttiContext.Create;
    for lType in ctx.GetTypes do
      if Units.IndexOf(GetUnitName(lType)) < 0 then
        Units.Add(GetUnitName(lType));
    Writeln(Units.Text);
  finally
    Units.Free;
  end;
end;

the question is, exist another reliable way to get the unit name of any TRttiType?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

歌枕肩 2024-10-02 18:33:37

信息就在那里,但解析限定名称是目前获取它的最佳方法。

如果您想以困难的方式做到这一点,您可以:

在 system.pas 单元中,您有一个变量 LibModuleList: PLibModule = nil; ,其中包含
已加载模块的列表。这是指向原始 RTTI 信息的指针,可以在没有 RTTI.pas 的情况下使用。您可以迭代所有原始信息来确定单位名称。

TLibModule 的关键值是:

  PLibModule = ^TLibModule;
  TLibModule = record
    Next: PLibModule;  { Linked List of Loaded Modules)
    Instance: LongWord;
    ...
    TypeInfo: PPackageTypeInfo; { List of contained Package Information }
    ...
  end;

使用 TypeInfo: PPackageTypeInfo; 您可以访问

  PPackageTypeInfo = ^TPackageTypeInfo;
  TPackageTypeInfo = record
    TypeCount: Integer;
    TypeTable: PTypeTable;
    UnitCount: Integer;
    UnitNames: PShortString; { concatenation of Pascal strings, 
                               one for each unit }
  end;

然后是 TypeTable,其中包含获取 PTypeInfo 的信息。
顺序。

  TTypeTable = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer;
  PTypeTable = ^TTypeTable;

可以在 Rtti.pas 中找到所有这些工作原理的示例,TPackage.MakeTypeLookupTable 是关键方法。此方法还表明 QualifiedName 始终包含 UnitName。因此,可以依赖您解析 QualfiedName 的原始方法。

The information is there but Parsing the Qualified Name is currently the best way to get to it.

If you want to do it the hard way you can by:

In the system.pas unit you have a variable LibModuleList: PLibModule = nil; that contains
the list of loaded modules. This is the pointer to the Raw RTTI Information that can be used without RTTI.pas. You could iterate all the raw information get determine the unit name.

The key values of the TLibModule are:

  PLibModule = ^TLibModule;
  TLibModule = record
    Next: PLibModule;  { Linked List of Loaded Modules)
    Instance: LongWord;
    ...
    TypeInfo: PPackageTypeInfo; { List of contained Package Information }
    ...
  end;

Using the TypeInfo: PPackageTypeInfo; you get access to

  PPackageTypeInfo = ^TPackageTypeInfo;
  TPackageTypeInfo = record
    TypeCount: Integer;
    TypeTable: PTypeTable;
    UnitCount: Integer;
    UnitNames: PShortString; { concatenation of Pascal strings, 
                               one for each unit }
  end;

Then there is TypeTable which contains the information to get to PTypeInfo.
sequence.

  TTypeTable = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer;
  PTypeTable = ^TTypeTable;

An example of how all this works can be found in Rtti.pas TPackage.MakeTypeLookupTable is the key method. This method also shows that QualifiedName always will contain the UnitName. As such your original method of parsing QualfiedName can be depended on.

薔薇婲 2024-10-02 18:33:37

看起来好像没有。 RTTI 来自 TTypeData 结构,该结构仅具有为特定类型显式声明的 UnitName 字段。 (这早于 D2010 和扩展 RTTI。)您的#2 看起来是获得它的最佳方法,并且如果他们要放入一个假设的 TRTTIObject.UnitName,则可能是这样计算它的。

It doesn't look like there is. The RTTI comes out of the TTypeData structure, which only has a UnitName field explicitly declared for specific types. (This predates D2010 and extended RTTI.) Your #2 looks like the best way to get it, and is probably how a hypothetical TRTTIObject.UnitName would calculate it if they were to put one in.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文