我该如何发布RTL单元的私有类函数?

7

Delphi XE3,System.Rtti.pas

我需要访问两个私有类函数,但我读到过,如果我修改RTL单元的接口部分,则需要重新编译所有RTL。这可不是胆小者可以做的事情!

这两个私有类函数在System.Rtti.pas中:

    class function GetName<T{: enum}>(AValue: T): string; reintroduce; static;
    class function GetValue<T{: enum}>(const AName: string): T; static;

System.Rtti.pas

  TRttiEnumerationType = class(TRttiOrdinalType)
  private
    function GetMaxValue: Longint; override;
    function GetMinValue: Longint; override;
    function GetUnderlyingType: TRttiType;
    constructor Create(APackage: TRttiPackage; AParent: TRttiObject; var P: PByte); override;
    {$HINTS OFF}
    function GetNames: TArray<string>;
    class function GetName<T{: enum}>(AValue: T): string; reintroduce; static;
    class function GetValue<T{: enum}>(const AName: string): T; static;
    {$HINTS ON}
  public
    property UnderlyingType: TRttiType read GetUnderlyingType;
  end;
2个回答

8

您还可以使用类助手来访问私有类方法。

program Project50;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,RTTI;

Type
  TRttiEnumerationTypeHelper = class helper for TRttiEnumerationType
  public
    class function Name<T>(AValue: T): string; inline;
    class function Value<T>(const AName: string): T; inline;
  end;

class function TRttiEnumerationTypeHelper.Name<T>(AValue: T): string;
begin
  Result := TRttiEnumerationType.GetName<T>(AValue);
end;

class function TRttiEnumerationTypeHelper.Value<T>(const AName: string): T;
begin
  Result := TRttiEnumerationType.GetValue<T>(AName);
end;

Type
  TEnum = (teTest1,teTest2,teTest3);

begin
  WriteLn( TRttiEnumerationType.Name<TEnum>(teTest1));
  WriteLn( Ord(TRttiEnumerationType.Value<TEnum>('teTest1')));
  ReadLn;
end.

它的缺点是另一个helper可能会隐藏这个声明。要使用它,只需将声明放在一个单元中,并在需要时包含该单元。

如果您想要函数的原始名称,请使用此处描述的技巧:Can I call static private class method with class helper?


有趣。我考虑过类助手,但不知道你可以使用它们来访问类函数。 - David Heffernan
Fabio,是的,另一个辅助程序可以做到这一点。如果它是已知的辅助程序,它们可以从一个继承到另一个。 - LU RD
这很有趣:必须小心,不要在其他单元中声明完全相同的类帮助器,如果包含,则可能会隐藏此声明。 - Fabio Vitale

2

以下是您的选择:

  1. 重新编译整个RTL。
  2. 使用RTTI访问私有方法。
  3. 向RTTI单元添加一个新类,以公开这些函数。据我所记,在接口部分添加类型或函数不会强制重新编译整个RTL。
  4. 在RTTI单元之外自行实现功能。例如,请参见此处的答案:将枚举转换为字符串和相反方向通用功能
  5. 使用类助手来破解私有内容,如LURD的答案中所述。

  1. 在接口部分添加类型或函数不会强制重新编译RTL。
当对RTL .pas单元进行更改时,是否会自动触发重新编译整个RTL过程?我认为后者是正确答案,但我不确定。非常感谢:答案#4是一个我可以接受的解决方法 :-)
- Fabio Vitale
不要自动触发。你真的想避免完全重新编译,因为你的直觉已经告诉你了。 - David Heffernan
选项4是我个人的选择。我认为你不需要为这样的操作调用新的风格RTTI。我认为选项4不是一个变通方法,而实际上是最好的选择。 - David Heffernan
实际上,我刚刚编译了选项4,并进行了一些测试,我非常喜欢它!我将尝试理解如何添加一些错误检查来避免尝试转换为不存在的枚举值。但是...这完全是另一个故事;-) 我同意你的观点,对于这种操作,没有必要使用新RTTI风格的语法糖!再次感谢你。 - Fabio Vitale
1
添加了选项5。它具有所有类/记录助手的缺点,但足够简单。 - LU RD
1
@LURD 看起来选民更喜欢你的答案而不是我的。代码的力量胜过言语,是吧? - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接