7

Delphi XE3, System.Rtti.pas

I need to access two private class functions, but I have read that if I modify the interface section of an RTL unit then I need to recompile all the RTL. Not for the faint heart!

The two private class functions are in 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;
Fabio Vitale
  • 2,257
  • 5
  • 28
  • 38

2 Answers2

8

You can also access the private class methods with a class helper.

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.

It has the drawback that another helper may hide this declaration. To use it, just put the declaration in a unit and include the unit wherever you need it.

If you want to have the original names of the functions, use the trick described here: Can I call static private class method with class helper?

Community
  • 1
  • 1
LU RD
  • 34,438
  • 5
  • 88
  • 296
  • Interesting. I considered class helpers but wasn't aware that you could use them to access class functions. – David Heffernan Aug 01 '15 at 08:43
  • Fabio, yes another helper may do that. If it is a known helper, they can inherit from one to another though. – LU RD Aug 01 '15 at 09:03
  • This is interesting: one must be careful not to declare the very same class helper in other units that can, if included, hide this declaration. – Fabio Vitale Aug 01 '15 at 09:03
2

Your options include:

  1. Recompiling the entire RTL.
  2. Using RTTI to access the private methods.
  3. Adding a new class to the RTTI unit that exposes the functions. As I recall, adding types or functions to the interface section won't force a total recompile of the RTL.
  4. Implementing the functionality yourself, outside the RTTI unit. For instance see the answers here: Generic functions for converting an enumeration to string and back.
  5. Use a class helper to crack the privates as described in LURD's answer.
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 3. [...] adding types or functions to the interface section won't force a total recompile of the RTL. Dees the process of recompiling the whole RTL thing is automatically triggered by changes to an RTL .pas unit or do I have to perform it manually? I think the last is correct answer, but I'm not sure. Thank you so much: answer #4 is a workaround that I can live with:-) – Fabio Vitale Aug 01 '15 at 06:16
  • Not automatically triggered. You really want to avoid total recompile as your instincts are already telling you. – David Heffernan Aug 01 '15 at 06:21
  • Option 4 is how I would do it personally. I don't think you need to invoke new style RTTI for such operations. I think option 4 is not so much workaround as in fact the best option. – David Heffernan Aug 01 '15 at 06:22
  • In fact I've just compiled Option 4 and played with it and I like it very much! I'll try to understand how can I add some error checking to avoid trying to convert to and from inexistent enumerations. But... this is completely another story;-) And I agree with you that for this kind of operations there is no need of the syntactic sugar of the new RTTI style! Thank you again. – Fabio Vitale Aug 01 '15 at 06:34
  • 1
    Added option 5. It has the drawbacks of all class/record helpers, but simple enough. – LU RD Aug 01 '15 at 08:12
  • 1
    @LURD Looks like the voters prefer your answer to mine. The power of code over words eh? – David Heffernan Aug 02 '15 at 04:47