コードの他の部分もフォームに属するプロパティを介して参照を取得するインターフェイスオブジェクトの背後にある機能を提供するDelphiフォームがあります。子オブジェクトにインターフェース機能を委任することはできません。その機能の多くがフォーム上のコントロール/コンポーネントによって提供されているためです。TFormクラスはTinterfacedObjectから継承せず、Delphiは多重継承をサポートしていないため、TAggregatedObjectまたはTContainedObjectを使用して、フォームに渡されるインターフェイスオブジェクトの存続期間をリンクできません。そのため、TInterfacedObjectを継承チェーンに混在させることはできません。 。この状況は、他のコードがフォームによって渡されたインターフェイス参照の1つを保持しているときにフォームが破棄された場合に、アクセス違反につながる可能性があります。誰かがこの問題の良い解決策を考えることができますか?
2 に答える
インターフェイスを子オブジェクトに委任できます。そのオブジェクトにフォームへの内部ポインタが含まれているだけで、必要なときにフォームのコントロールにアクセスできます。これは、現在実行しているものと同じです。
あなたはまたはあなたのニーズのために使うことができTAggregateObject
ますTContainedObject
。フォームをから派生させる必要はありませんTInterfacedObject
。必要なのはIInterface
インターフェイスポインタだけであり、からTComponent
派生し(およびIInterface
をオーバーライドして参照カウントを無効にする)、フォーム自体(子孫である)を必要なポインタとして渡すことができます。_AddRef()
_Release()
TComponent
IInterface
それが残っている唯一の問題を残します-アクティブなインターフェース参照が他のコードによって保持されている間にフォームが閉じます。最も簡単な解決策は、1)フォームが閉じている間、それらの参照を保持しないようにコードを書き直すか、2)それらの参照が解放されるまでフォームを閉じないようにすることです。
注:これは、コンシューマーがTComponentからも派生している場合にのみ機能します。
デッドリファレンスを回避するにはIInterfaceComponentReference
、フォームから(すべてのTComponentで使用可能)クエリを実行しGetComponent
、そのインターフェイスを呼び出してFreeNotification
、返されたコンポーネント/フォームに接続します。
現在何が起こっているか:フォームが破棄されると、すべての「リスナー」に、それ自体(フォーム)を操作として使用してコンシューマーのメソッドを呼び出すことにより、フォームが破棄されることを通知しNotification
ます。したがって、インターフェイス参照をゼロにすることができます。ただし、オブジェクト参照とインターフェイス参照は等しくてはならないことに注意してください。また、不要な電話を避けるために、通知が不要になったときに必ず電話をかけてください。AComponent
opRemove
RemoveFreeNotification
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;