12

我需要修复第三方组件。这个组件的类有私有变量,被它的后代积极使用:

TThirdPartyComponentBase = class
private
  FSomeVar: Integer;
public
  ...
end;

TThirdPartyComponent = class (TThirdPartyComponentBase)
protected
   procedure Foo; virtual;
end;

procedure TThirdPartyComponent.Foo;
begin
  FSomeVar := 1; // ACCESSING PRIVATE FIELD!
end; 

这是有效的,因为两个班级都在同一个单元中,所以他们有点“朋友”。

但是如果我尝试在一个新单元中创建一个新类

TMyFixedComponent = class (TThirdPartyComponent)
  procedure Foo; override; 
end;

我无法再访问 FSomeVar,但我需要将其用于修复。而且我真的不想在我的代码中重现所有基类树。

如果可能的话,您能否建议一些快速破解来访问该私有字段而不更改原始组件的单元

4

4 回答 4

20

通过使用class helpers它可以完成从派生类对基类私有部分的访问,而不会失去类型安全性。

只需在另一个单元中添加这些声明:

Uses YourThirdPartyComponent;

type
  // A helper to the base class to expose FSomeVar
  TMyBaseHelper = class helper for TThirdPartyComponentBase
  private
    procedure SetSomeVar( value : integer);
    function GetSomeVar: integer;
  public
    property SomeVar:integer read GetSomeVar write SetSomeVar;
  end;

  TMyFixedComponent = class helper for TThirdPartyComponent
  protected
    procedure Foo;
  end;

procedure TMyFixedComponent.Foo;
begin
  // Cast to base class and by the class helper TMyBaseHelper the access is resolved
  TThirdPartyComponentBase(Self).SomeVar := 1; 
end;

function TMyBaseHelper.GetSomeVar: integer;
begin
  Result := Self.FSomeVar; // ACCESSING PRIVATE FIELD!
end;

procedure TMyBaseHelper.SetSomeVar(value: integer);
begin
  Self.FSomeVar := value; // ACCESSING PRIVATE FIELD!
end;

// Testing
var
  TSV: TThirdPartyComponent;
begin
  TSV := TThirdPartyComponent.Create;
  try
    TSV.Foo;    
    WriteLn(IntToStr(TSV.SomeVar));  // Writes 1
  finally
    TSV.Free;
  end;
end.

从代码中的注释可以看出,FSomeVar由类中的类助手公开TThirdPartyComponentBaseTThirdPartyComponent另一个实现 Foo 过程的类助手。在那里,SomeVar对基类助手的属性的访问是通过类型转换为基类进行的。

于 2012-07-07T22:13:29.080 回答
6

您必须使用 hack 来访问不同单元中任何类(包括基类)中的私有字段。在您的情况下,在您的单位中定义:

type
  __TThirdPartyComponentBase = class 
  private 
    FSomeVar: Integer;
  end;

然后获取访问权限:

__TThirdPartyComponentBase(Self).FSomeVar := 123;

当然,这很危险,因为您需要控制基类中的更改。因为如果字段布局将被更改并且您会错过这个事实,那么上述方法将导致失败、AV 等。

于 2010-10-28T14:13:14.610 回答
0

不知道这是否会有所帮助,但我似乎记得有一种方法可以将私有变量“破解”为可见性。

例如,我知道,当我将属性从较低的可见性(在基类中)移动到更可见的级别(在我的后代中)时,我遇到了来自编译器的警告。警告称它正在以不同的可见性级别宣布......

已经有一段时间了,我不确定,但我相信你能做的就是在你的后代中声明与受保护的变量相同的变量。(您可能必须使用 Redeclare 关键字进行编译。)

抱歉,我没有关于如何执行此操作的更具体信息(如果确实可能的话。)也许这篇文章会提示这里的一位向导纠正我!:-)

于 2010-10-28T16:15:28.907 回答
-1

通过 TThirdPartyComponent 中的受保护属性公开私有变量的值。

TThirdPartyComponent = class (TThirdPartyComponentBase)
private
   Procedure SetValue(Value: Integer);
   Function GetValue: Integer;
protected
   Property MyVar: Integer read GetValue write Setvalue; 
   procedure Foo; virtual;
end;

Procedure TThirdPartyComponent.SetValue(Value: Integer);
begin
  FSomeVar := Value ;
end;

Function GetValue: Integer;
begin
  result := FSomeVar;
end;

TMyFixedComponent课堂上使用MyVar您想要覆盖的过程中的属性。

于 2010-10-28T14:01:01.460 回答