2011-10-10 3 views
7

필자는 인터페이스 객체 뒤에있는 기능을 제공하는 Delphi Form을 사용하여 코드의 다른 부분도 Form에 속한 속성을 통해 참조를 얻습니다. 너무 많은 기능이 컨트롤/폼의 구성 요소에 의해 처리되기 때문에 인터페이스 기능을 자식 개체에 위임 할 수 없습니다. TAFPregatedObject 또는 TContainedObject를 사용하여 TForm 클래스가 TinterfacedObject에서 상속되지 않고 Delphi에서 상속 체인에 TInterfacedObject를 혼합 할 수 없기 때문에 다중 상속을 지원하지 않기 때문에 Form으로 전달되는 인터페이스 객체의 수명을 연결할 수 없습니다. . 양식에 의해 전달 된 인터페이스 참조 중 하나가 다른 코드에있는 동안 양식이 삭제되면이 상황으로 인해 액세스 위반이 발생할 수 있습니다. 누구든지이 문제에 대한 좋은 해결책을 생각할 수 있습니까?Delphi에서 일생에 연결된 인터페이스 객체를 배포하기위한 Form을위한 안전한 방법은 무엇입니까?

답변

9

인터페이스를 하위 개체에 위임 할 수 있습니다.이 개체에 폼에 대한 내부 포인터가 포함되어 있으면 필요할 때 폼 컨트롤에 액세스 할 수 있습니다.

TAggregateObject 또는 TContainedObject을 사용할 수 있습니다. 그들은 TInterfacedObject에서 파생 된 양식을 요구하지 않습니다. 그들이 필요로 할 모든은 IInterface 인터페이스 포인터이며, TComponentIInterface에서 파생 (참조 카운팅을 비활성화 _AddRef()_Release()을 무시), 그래서 당신은 양식 자체가 필요 IInterface 포인터의 (a TComponent 후손 인) 전달할 수 있습니다.

나머지 문제는 남아 있습니다 - 활성 인터페이스 참조가 다른 코드에 의해 유지되는 동안 양식이 닫힙니다. 가장 간단한 해결책은 1) 양식이 닫히는 동안 해당 참조를 보유하지 않도록 코드를 다시 작성하거나 2) 해당 참조가 해제 될 때까지 양식을 닫지 못하도록하는 것입니다.

+0

Lebeau, 저의 정보를 사용하여 코드를 수정 해 드리겠습니다. –

+0

늦은 질문을 실례하지만, TAggregatedObject 대신 TContainedObject를 사용해야 할 때를 설명하는 좋은 참고 자료를 가르쳐 주시겠습니까? 나는 델파이 도움말을 한동안 쳐다 보았고 유스 케이스의 차이를 실제로 살릴 수는 없다. –

2

참고 : 이는 소비자가 TComponent에서 파생 된 경우에만 작동합니다.

는 양식에서 (모든 TComponent의에서 사용 가능) IInterfaceComponentReference는, 그 인터페이스에 GetComponent를 호출하고 반환 구성 요소/형태의 FreeNotification에 자신을 첨부 조회 할 수 있습니다 죽은 참조를 방지하려면.

무엇 이제 어떻게 것은 : 양식이 파괴됩니다 때 그것이 AComponent 및 운영 등 opRemove로 자체 (양식)와 소비자에 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) 두 번째로 인터페이스를 매번 새로운 Object를 다시 만들 수있는 속성 (Win32)에 위임 할 수 있습니다. c) TObject.GetInterface를 구현하면 주소에 interfaceOffset이 추가됩니다. 객체 캐스팅에 새로 도입 된 (Delphi 2010) 인터페이스는 기본적으로 객체의 입력 주소를 반환하는 마커 인터페이스를 쿼리하여 수행됩니다. –

+0

객체와 인터페이스 참조가 동일하고 프로그래머가 원치 않는 상황을 만드는 가장 흔한 실수는 무엇입니까? –