delphi मददगार के बिना निजी तरीकों का उपयोग कैसे करें?




private delphi-10.1-berlin (4)

डेल्फी 10 सिएटल में मैं अत्यधिक सख्त दृश्यता प्रतिबंधों के आसपास काम करने के लिए निम्न कोड का उपयोग कर सकता हूं।

मैं निजी चरों तक पहुंच कैसे प्राप्त करूं?

type 
  TBase = class(TObject)
  private
    FMemberVar: integer;
  end;

और मैं सादे या आभासी निजी तरीकों तक पहुंच कैसे प्राप्त करूं?

type
  TBase2 = class(TObject) 
  private
    procedure UsefullButHidden;  
    procedure VirtualHidden; virtual;
    procedure PreviouslyProtected; override;
  end;

पहले मैं बेस क्लास खोलने के लिए एक कक्षा सहायक का उपयोग करता था।

type
  TBaseHelper = class helper for TBase
    function GetMemberVar: integer;

डेल्फी 10.1 बर्लिन में, क्लास हेल्पर्स को अब विषय वर्ग या रिकॉर्ड के निजी सदस्यों तक पहुंच नहीं है।

क्या निजी सदस्यों तक पहुंचने का कोई वैकल्पिक तरीका है?


अगर आपको एआरएम कंपाइलर समर्थन की आवश्यकता नहीं है , तो आप here एक और समाधान पा सकते हैं।

इनलाइन असेंबलर के साथ, आप आसानी से निजी क्षेत्र या विधि तक पहुंच सकते हैं।

मुझे लगता है कि ज्यादातर मामलों में डेविड का जवाब बेहतर है, लेकिन यदि आपको एक विशाल वर्ग के लिए त्वरित समाधान की आवश्यकता है, तो यह विधि अधिक उपयोगी हो सकती है।

अपडेट (17 जून): मैंने अभी देखा है, मैं अपने here से निजी फ़ील्ड तक पहुंचने के लिए अपना नमूना कोड साझा करना भूल गया था। माफ़ कीजिये।

unit UnitA;

type
  THoge = class
  private
    FPrivateValue: Integer;
    procedure PrivateMethod;
  end;
end.

unit UnitB;

type
  THogeHelper = class helper for THoge
  public
    function GetValue: Integer;
    procedure CallMethod;
  end;

function THogeHelper.GetValue: Integer;
asm
  MOV EAX,Self.FPrivateValue
end;

procedure THogeHelper.CallMethod;
asm
  CALL THoge.PrivateMethod
end;

निजी विधि को कॉल करने के लिए उसका नमूना कोड यहां दिया गया है।

type
  THoge = class
  private
    procedure PrivateMethod (Arg1, Arg2, Arg3 : Integer);
  end;

// Method 1
// Get only method pointer (if such there is a need to assign a method pointer to somewhere)
type
  THogePrivateProc = procedure (Self: THoge; Arg1, Arg2, Arg3: Integer);
  THogePrivateMethod = procedure (Arg1, Arg2, Arg3: Integer) of object;

function THogeHelper.GetMethodAddr: Pointer;
asm
  {$ifdef CPUX86}
  LEA EAX, THoge.PrivateMethod
  {$else}
  LEA RAX, THoge.PrivateMethod
  {$endif}
end;

var
  hoge: THoge;
  proc: THogePrivateProc;
  method: THogePrivateMethod;
begin
  // You can either in here of the way,
  proc := hoge.GetMethodAddr;
  proc (hoge, 1, 2, 3);
  // Even here of how good
  TMethod (method) .Code := hoge.GetMethodAddr;
  TMethod (method) .Data := hoge;
  method (1, 2, 3) ;
end;

// Method 2
// To jump (here is simple if you just simply call)
procedure THogeHelper.CallMethod (Arg1, Arg2, Arg3 : Integer);
asm
  JMP THoge.PrivateMethod
end;

unit UnitA;

type
  THoge = class
  private
    FPrivateValue: Integer;
    procedure PrivateMethod;
  end;
end.

यदि आप एक साफ तरीका चाहते हैं जो प्रदर्शन को प्रभावित नहीं करता है, तो भी आप कथन के साथ रिकॉर्ड हेल्पर से निजी फ़ील्ड तक पहुंच सकते हैं।

function TValueHelper.GetAsInteger: Integer;
begin
  with Self do begin
    Result := FData.FAsSLong;
  end;
end;

मुझे आशा है कि वे इस विधि को खुले रखें, क्योंकि हमारे पास उच्च प्रदर्शन मांगों वाला कोड है।


यदि श्रेणी के निजी सदस्यों के लिए जेनरेट की गई आरटीटीआई जानकारी है - फ़ील्ड और / या विधियों का उपयोग आप उन्हें प्राप्त करने के लिए कर सकते हैं।

बेशक, आरटीटीआई के माध्यम से पहुंच वर्ग की मददगारों की तुलना में धीमी है।

एक्सेसिंग विधियां:

var
  Base: TBase2;
  Method: TRttiMethod;

  Method := TRttiContext.Create.GetType(TBase2).GetMethod('UsefullButHidden');
  Method.Invoke(Base, []);

चर का उपयोग:

var
  Base: TBase;
  v: TValue;

  v := TRttiContext.Create.GetType(TBase).GetField('FMemberVar').GetValue(Base);

आरटीएल / वीसीएल / एफएमएक्स कक्षाओं के लिए उत्पन्न डिफ़ॉल्ट आरटीटीआई जानकारी निम्नलिखित है

  • फ़ील्ड - private , protected , public , published
  • तरीके - public , published
  • गुण - public , published

दुर्भाग्यवश, इसका मतलब है कि मूल डेल्फी पुस्तकालयों के लिए आरटीटीआई के माध्यम से निजी तरीकों तक पहुंच उपलब्ध नहीं है। @ एलयू आरडी के जवाब में हैक शामिल है जो विस्तारित आरटीटीआई के बिना कक्षाओं के लिए निजी विधि पहुंच की अनुमति देता है।

आरटीटीआई के साथ काम करना


डेल्फी 10.1 में निजी तरीकों के उपयोग के लिए class helpers का उपयोग करने का अभी भी एक तरीका है बर्लिन:

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;

दुर्भाग्य से डेल्फी 10.1 बर्लिन के साथ कक्षा सहायकों द्वारा सख्त निजी / निजी क्षेत्रों तक पहुंचने का कोई तरीका नहीं है। आरटीटीआई एक विकल्प है, लेकिन प्रदर्शन महत्वपूर्ण है तो धीमा माना जा सकता है।

क्लास हेल्पर्स और आरटीटीआई का उपयोग करके स्टार्टअप पर ऑफ़सेट को परिभाषित करने का एक तरीका यहां दिया गया है:

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;

इससे लाभ होगा कि धीमी आरटीटीआई भाग केवल एक बार निष्पादित की जाती है।

नोट: संरक्षित / निजी तरीकों के उपयोग के लिए आरटीटीआई का उपयोग करना

आरटीएल / वीसीएल / एफएमएक्स ने आरटीटीआई के साथ संरक्षित / निजी तरीकों की पहुंच के लिए दृश्यता घोषित नहीं की है। इसे स्थानीय निर्देश {$RTTI} साथ सेट किया जाना चाहिए।

अन्य कोड में निजी / संरक्षित तरीकों के उपयोग के लिए आरटीटीआई का उपयोग उदाहरण सेटिंग के लिए आवश्यक है:

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




delphi-10.1-berlin