How to access private methods without helpers?

前端 未结 6 2030
孤独总比滥情好
孤独总比滥情好 2020-11-28 06:39

In Delphi 10 Seattle I could use the following code to work around overly strict visibility restrictions.

How do I get access to private variables?



        
6条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-28 07:25

    There is still a way to use class helpers for access of private methods in Delphi 10.1 Berlin:

    type
      TBase2 = class(TObject) 
      private
        procedure UsefullButHidden;  
        procedure VirtualHidden; virtual;
        procedure PreviouslyProtected; override;
      end;
    
      TBase2Helper = class helper for TBase2
        procedure OpenAccess;
      end;
    
      procedure TBase2Helper.OpenAccess;
      var
        P : procedure of object;
      begin
        TMethod(P).Code := @TBase2.UsefullButHidden;
        TMethod(P).Data := Self;
        P; // Call UsefullButHidden;
        // etc
      end;
    

    Unfortunately there is no way to access strict private/private fields by class helpers with Delphi 10.1 Berlin. RTTI is an option, but can be considered slow if performance is critical.

    Here is a way to define the offset to a field at startup using class helpers and RTTI:

    type 
      TBase = class(TObject)
      private  // Or strict private
        FMemberVar: integer;
      end;
    
    type
      TBaseHelper = class helper for TBase
      private
        class var MemberVarOffset: Integer;
        function GetMemberVar: Integer;
        procedure SetMemberVar(value: Integer);
      public
        class constructor Create;  // Executed at program start
        property MemberVar : Integer read GetMemberVar write SetMemberVar;
      end;
    
    class constructor TBaseHelper.Create;
    var
      ctx: TRTTIContext;
    begin
      MemberVarOffset := ctx.GetType(TBase).GetField('FMemberVar').Offset;
    end;
    
    function TBaseHelper.GetMemberVar: Integer;
    begin
      Result := PInteger(Pointer(NativeInt(Self) + MemberVarOffset))^;
    end;
    
    procedure TBaseHelper.SetMemberVar(value: Integer);
    begin
      PInteger(Pointer(NativeInt(Self) + MemberVarOffset))^ := value;
    end;
    

    This will have the benefit that the slow RTTI part is only executed once.


    Note: Using RTTI for access of protected/private methods

    The RTL/VCL/FMX have not declared visibility for access of protected/private methods with RTTI. It must be set with the local directive {$RTTI}.

    Using RTTI for access of private/protected methods in other code requires for example setting :

    {$RTTI EXPLICIT METHODS([vcPublic, vcProtected, vcPrivate])}
    

提交回复
热议问题