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、クラスのクラスヘルパーによって公開されていTThirdPartyComponentBaseます。TThirdPartyComponentFooプロシージャを実装するための別のクラスヘルパー。そこでSomeVarは、基本クラスヘルパーのプロパティへのアクセスは、基本クラスにキャストされた型を介して行われます。

于 2012-07-07T22:13:29.080 に答える
6

別のユニットの任意のクラス (基本クラスを含む) のプライベート フィールドにアクセスするには、ハックを使用する必要があります。あなたの場合、あなたのユニットで定義してください:

type
  __TThirdPartyComponentBase = class 
  private 
    FSomeVar: Integer;
  end;

次に、アクセスを取得します。

__TThirdPartyComponentBase(Self).FSomeVar := 123;

もちろん、基本クラスの変更を制御する必要があるため、これは危険です。フィールドのレイアウトが変更され、この事実を見逃すと、上記のアプローチは失敗や AV などにつながるためです。

于 2010-10-28T14:13:14.610 に答える
0

これが役立つかどうかはわかりませんが、プライベート変数を「クラック」して可視化する方法があることを思い出したようです。

たとえば、プロパティを低い可視性 (基本クラス) からより可視性の高いレベル (子孫) に移動したときに、コンパイラから警告が表示されたことは知っています。警告は、それが異なるレベルの可視性で宣言されていると述べました...

しばらく経ちましたが、確かではありませんが、あなたができることは、子孫で同じ変数を保護されていると宣言することだと思います。(これをコンパイルするには、Redeclare キーワードを使用する必要がある場合があります。)

申し訳ありませんが、これを行う方法に関する具体的な情報はありません (実際に可能である場合)。おそらく、この投稿により、ここにいるウィザードの 1 人が私を修正するよう促されるでしょう! :-)

于 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 に答える