variable una polimorfismo otra misma metodo llamar herencia desde derivada como clase delphi private delphi-10.1-berlin

delphi - una - ¿Cómo acceder a métodos privados sin ayudantes?



llamar variable de otra clase java (5)

Si desea una forma limpia que no afecte el rendimiento, aún puede acceder a campos privados desde un asistente de registro utilizando la instrucción with.

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

Espero que mantengan este método abierto, porque tenemos código con demandas de alto rendimiento.

En Delphi 10 Seattle podría usar el siguiente código para evitar restricciones de visibilidad demasiado estrictas.

¿Cómo obtengo acceso a variables privadas?

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

¿Y cómo obtengo acceso a métodos privados simples o virtuales?

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

Anteriormente, usaría un ayudante de clase para abrir la clase base.

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

En Delphi 10.1 Berlín, los ayudantes de clase ya no tienen acceso a miembros privados de la clase o registro de la asignatura.

¿Hay alguna forma alternativa de acceder a miembros privados?


Si se genera información RTTI extendida para los miembros privados de la clase: campos y / o métodos, puede usarla para obtener acceso a ellos.

Por supuesto, acceder a través de RTTI es mucho más lento que a través de los ayudantes de clase.

Métodos de acceso:

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

Acceso a variables:

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

La información RTTI predeterminada generada para las clases RTL / VCL / FMX está siguiendo

  • Campos: private , protected , public , published
  • Métodos: public , published
  • Propiedades public published

Desafortunadamente, eso significa que el acceso a métodos privados a través de RTTI para las bibliotecas principales de Delphi no está disponible. La respuesta de @LU RD cubre el pirateo que permite el acceso a métodos privados para clases sin RTTI extendido.

Trabajando con RTTI


Suponiendo que RTTI extendido no está disponible, entonces, sin recurrir a lo que se consideraría piratería, no puede acceder a miembros privados desde el código en una unidad diferente. Por supuesto, si RTTI está disponible, se puede usar.

Tengo entendido que la capacidad de descifrar miembros privados usando ayudantes fue un accidente no intencional. La intención es que los miembros privados solo sean visibles desde el código en la misma unidad, y los miembros privados estrictos solo sean visibles desde el código en la misma clase. Este cambio corrige el accidente.

Sin la capacidad de que el compilador descifre la clase por usted, necesitaría recurrir a otras formas de hacerlo. Por ejemplo, puede volver a declarar suficiente de la clase TBase para poder engañar al compilador para que le diga dónde vivía un miembro.

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

Ahora puedes escribir

var obj: TBase; .... MemberVar := THackBase(obj).FMemberVar;

Pero esto es terriblemente frágil y se romperá tan pronto como se cambie el diseño de TBase .

Eso funcionará para los miembros de datos, pero para los métodos no virtuales, probablemente necesitará usar técnicas de desmontaje en tiempo de ejecución para encontrar la ubicación del código. Para los miembros virtuales, esta técnica se puede utilizar para encontrar el desplazamiento de VMT.

Otras lecturas:


Todavía hay una manera de usar class helpers para acceder a métodos privados en Delphi 10.1 Berlín:

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;

Desafortunadamente, no hay forma de acceder a campos privados / privados estrictos por los ayudantes de clase con Delphi 10.1 Berlín. RTTI es una opción, pero puede considerarse lento si el rendimiento es crítico.

Aquí hay una manera de definir el desplazamiento de un campo en el inicio utilizando ayudantes de clase y 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;

Esto tendrá el beneficio de que la parte RTTI lenta solo se ejecuta una vez.

Nota: Uso de RTTI para acceder a métodos protegidos / privados

El RTL / VCL / FMX no ha declarado visibilidad para acceder a métodos protegidos / privados con RTTI. Debe establecerse con la directiva local {$RTTI} .

El uso de RTTI para acceder a métodos privados / protegidos en otro código requiere, por ejemplo, la configuración:

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


Si no necesita compatibilidad con el compilador ARM , puede encontrar otra solución here .

Con el ensamblador en línea, puede acceder fácilmente a un campo o método privado.

Creo que la respuesta de David es mejor en la mayoría de los casos, pero si necesita una solución rápida para una gran clase, este método podría ser más útil.

Actualización (17 de junio): Acabo de darme cuenta, olvidé compartir su código de muestra para acceder a campos privados desde su here . lo siento.

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;

Aquí está su código de muestra para llamar al método privado .

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.