2011-10-10 9 views
7

Ho un modulo Delphi che fornisce la funzionalità dietro un oggetto di interfaccia che altre parti del codice ottengono riferimenti anche tramite una proprietà che appartiene al modulo. Non è possibile delegare la funzionalità dell'interfaccia a un oggetto figlio poiché troppe funzionalità vengono gestite da controlli/componenti nel modulo. Non posso usare TAggregatedObject o TContainedObject per collegare la durata degli oggetti interfacciati passati al Form perché la classe TForm non eredita da TinterfacedObject e Delphi non supporta l'ereditarietà multipla quindi non posso mischiare TInterfacedObject nella catena di ereditarietà . Questa situazione può portare a violazioni di accesso se un modulo viene distrutto mentre un altro codice contiene uno dei riferimenti all'interfaccia distribuiti dal modulo. Qualcuno può pensare ad una buona soluzione a questo problema?Un modo sicuro in Delphi per un modulo per distribuire oggetti di interfaccia legati alla sua durata?

risposta

9

È possibile delegare l'interfaccia per un oggetto figlio, basta avere quell'oggetto contiene un puntatore interno al modulo in modo che possa accedere ai controlli del modulo in caso di necessità, non è diverso allora si sta già facendo in questo momento.

È possibile utilizzare TAggregateObject o TContainedObject per le proprie esigenze. Non richiedono che il modulo derivi da TInterfacedObject. Tutto quello che richiedono è un puntatore IInterface interfaccia, e TComponent deriva da IInterface (e sostituisce il _AddRef() e _Release() per disattivare il conteggio di riferimento), in modo da poter passare la forma stessa (essendo discendente TComponent) come IInterface puntatore richiesto.

Questo lascia l'unico problema rimanente: la chiusura del modulo mentre i riferimenti di interfaccia attivi sono trattenuti da un altro codice. La soluzione più semplice è quella di 1) riscrivere quel codice per non mantenere tali riferimenti mentre il modulo si sta chiudendo, oppure 2) non consentire al modulo di chiudersi fino a quando questi riferimenti non sono stati rilasciati.

+0

Lebeau, grazie Userò queste informazioni per rivedere il mio codice. –

+0

Perdonate la domanda in ritardo, ma potete indicarmi un buon riferimento che spieghi quando utilizzare TContainedObject anziché TAggregatedObject? Ho guardato l'Aiuto Delphi per un po 'e non riesco a capire le differenze tra maiuscole e minuscole. –

2

Nota: Ciò funzionerà solo se il consumatore è anche derivato da TComponent.

Per evitare i riferimenti morti è possibile interrogare il IInterfaceComponentReference (disponibile su ogni TComponent) dal modulo, chiami GetComponent su tale interfaccia e collegare se stessi al FreeNotification della tornata Componente/Modulo.

Quello che succede ora è: quando il modulo viene distrutta ne informa tutte le "listners" che la sua intenzione di distruggere se stessa chiamando il metodo Notification sul consumatore con se stessa (forma) come AComponent e opRemove come il funzionamento. In questo modo è possibile annullare il riferimento all'interfaccia. Ma attenzione che i riferimenti agli oggetti e i riferimenti all'interfaccia non devono essere uguali. Assicurati inoltre di chiamare RemoveFreeNotification quando non hai più bisogno della notifica per evitare chiamate inutili.

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

Bello! Non lo sapevo. Potresti espandere un po 'la tua affermazione - "Ma tieni presente che i riferimenti a oggetti e i riferimenti all'interfaccia non devono essere uguali."? –

+1

Bene, diversi motivi: a) è possibile eseguire un'implementazione personalizzata di 'QueryInterface' che può restituire un nuovo oggetto interfacciato su ogni chiamata. b) In secondo luogo è possibile delegare l'interfaccia a una proprietà (Win32), che potrebbe creare nuovamente un nuovo oggetto ogni volta. c) L'implementazione di 'TObject.GetInterface' aggiunge un'interfacciaOffset all'indirizzo.(Ma questi interni sono, purtroppo, al di là della conoscenza maggio) La recente introduzione (Delphi 2010) Interfaccia di opporsi fusione è sostanzialmente fatto interrogando un'interfaccia marcatore, che restituisce l'indirizzo entrata dell'oggetto. –

+0

Cosa succederà se i riferimenti a oggetti e interfacce sono uguali e qual è l'errore più comune da parte di un programmatore che finisce per creare quella situazione indesiderata? –

Problemi correlati