2011-10-10 7 views
7

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

答えて

9

インターフェイスを子オブジェクトに委譲できます。そのオブジェクトにフォームへの内部ポインタが含まれているだけで、必要に応じてフォームのコントロールにアクセスできます。

TAggregateObjectまたはTContainedObjectをご利用いただけます。フォームはTInterfacedObjectから派生する必要はありません。彼らは必要ないすべてはIInterfaceインタフェースポインタで、TComponentIInterfaceから派生(および参照カウントを無効にする_AddRef()_Release()が上書きされます)ので、あなたが必要IInterfaceポインタとして(TComponent子孫である)フォーム自体を渡すことができます。

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

+0

ルボー、私のコードを改訂するためにその情報を使用します。 –

+0

遅れてご質問をお待ちしていますが、TAggregatedObjectの代わりにTContainedObjectを使用するタイミングを説明する良いリファレンスを教えてください。私はしばらくの間、Delphiのヘルプを見てきましたし、実際にユースケースの違いを洗い出すことはできません。 –

2

注:消費者がTComponentから派生している場合にのみ、これは機能します。フォームからあなたが(すべてのTComponentの上で利用可能)IInterfaceComponentReferenceを照会することができます死んだ言及を避けるために

、そのインターフェイス上GetComponentを呼び出し、返されたコンポーネント/フォームのFreeNotificationに自分自身を添付します。今、何が起こる

は次のとおりです。フォームは、その操作などAComponentopRemoveとしての地位を消費者(フォーム)にNotificationメソッドを呼び出すことによって、自分自身を破壊しようとしていることをすべて「listners」を通知します破棄されますとき。したがって、あなたはあなたのインターフェイス参照をゼロにすることができます。 しかし、オブジェクト参照とインタフェース参照は同じであってはならないことに注意してください。 不要な通話を避けるために通知が不要な場合は、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; 
+0

ニース!私はそれについて知らなかった。あなたのステートメントで少し拡張することができます - "しかし、オブジェクト参照とインターフェイス参照が等しくあってはならないことに注意してください。" –

+1

まあ、いくつかの理由: a)すべての呼び出しで新しいインタフェースオブジェクトを返すかもしれない 'QueryInterface'のカスタム実装を作ることができます。 b)次にInterfaceをプロパティ(Win32)に委譲することができます。これにより、毎回新しいObjectを作成することができます。 c)TObject.GetInterfaceを実装すると、アドレスにinterfaceOffsetが追加されます。 オブジェクトキャストへの新しく導入された(Delphi 2010)インターフェイスは、基本的に、オブジェクトのエントリアドレスを返すマーカーインターフェイスを照会することによって実行されます。 –

+0

オブジェクトとインターフェイスの参照が等しく、プログラマが間違った状況を作り出す最も一般的な間違いは何ですか? –

関連する問題