7

コードの他の部分もフォームに属するプロパティを介して参照を取得するインターフェイスオブジェクトの背後にある機能を提供するDelphiフォームがあります。子オブジェクトにインターフェース機能を委任することはできません。その機能の多くがフォーム上のコントロール/コンポーネントによって提供されているためです。TFormクラスはTinterfacedObjectから継承せず、Delphiは多重継承をサポートしていないため、TAggregatedObjectまたはTContainedObjectを使用して、フォームに渡されるインターフェイスオブジェクトの存続期間をリンクできません。そのため、TInterfacedObjectを継承チェーンに混在させることはできません。 。この状況は、他のコードがフォームによって渡されたインターフェイス参照の1つを保持しているときにフォームが破棄された場合に、アクセス違反につながる可能性があります。誰かがこの問題の良い解決策を考えることができますか?

4

2 に答える 2

9

インターフェイスを子オブジェクトに委任できます。そのオブジェクトにフォームへの内部ポインタが含まれているだけで、必要なときにフォームのコントロールにアクセスできます。これは、現在実行しているものと同じです。

あなたはまたはあなたのニーズのために使うことができTAggregateObjectますTContainedObject。フォームをから派生させる必要はありませんTInterfacedObject。必要なのはIInterfaceインターフェイスポインタだけであり、からTComponent派生し(およびIInterfaceをオーバーライドして参照カウントを無効にする)、フォーム自体(子孫である)を必要なポインタとして渡すことができます。_AddRef()_Release()TComponentIInterface

それが残っている唯一の問題を残します-アクティブなインターフェース参照が他のコードによって保持されている間にフォームが閉じます。最も簡単な解決策は、1)フォームが閉じている間、それらの参照を保持しないようにコードを書き直すか、2)それらの参照が解放されるまでフォームを閉じないようにすることです。

于 2011-10-10T23:57:01.590 に答える
2

注:これは、コンシューマーがTComponentからも派生している場合にのみ機能します。

デッドリファレンスを回避するにはIInterfaceComponentReference、フォームから(すべてのTComponentで使用可能)クエリを実行しGetComponent、そのインターフェイスを呼び出してFreeNotification、返されたコンポーネント/フォームに接続します。

現在何が起こっているか:フォームが破棄されると、すべての「リスナー」に、それ自体(フォーム)を操作として使用してコンシューマーのメソッドを呼び出すことにより、フォームが破棄されることを通知しNotificationます。したがって、インターフェイス参照をゼロにすることができます。ただし、オブジェクト参照とインターフェイス参照は等しくてはならないことに注意してください。また、不要な電話を避けるために、通知が不要になったときに必ず電話をかけてください。AComponentopRemoveRemoveFreeNotification

TSomeConsumer = class(TComponent)
private
  FInterfaceToAService: ISomeInterface;        
protected
  procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
  procedure SetService(const Value: ISomeInterface); 
end;

procedure TSomeConsumer.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = TObject(FInterfaceToAService)) then
    SetService(nil); // Takes care of niling the interface as well.
end;

procedure TSomeConsumer.SetService(const Value: ISomeInterface);
var
  comRef: IInterfaceComponentReference;
begin
  if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
    comRef.GetComponent.RemoveFreeNotification(self);

  FInterfaceToAService := Value;

  if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
    comRef.GetComponent.FreeNotification(self);
end;
于 2011-10-11T09:48:27.737 に答える