2013-04-25 10 views
13

Mi aspetto che il conteggio dei riferimenti funzioni sull'oggetto aggregante esterno in un'implementazione dell'interfaccia. Se può riferirsi a un altro esempio: Clarity in classes implementing multiple interfaces (alternative to delegation):Strumenti interfaccia Delphi

Ecco una riproduzione minimo del comportamento:

program SO16210993; 

{$APPTYPE CONSOLE} 

type 
    IFoo = interface 
    procedure Foo; 
    end; 

    TFooImpl = class(TInterfacedObject, IFoo) 
    procedure Foo; 
    end; 

    TContainer = class(TInterfacedObject, IFoo) 
    private 
    FFoo: IFoo; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    property Foo: IFoo read FFoo implements IFoo; 
    end; 

procedure TFooImpl.Foo; 
begin 
    Writeln('TFooImpl.Foo called'); 
end; 

constructor TContainer.Create; 
begin 
    inherited; 
    FFoo := TFooImpl.Create; 
end; 

destructor TContainer.Destroy; 
begin 
    Writeln('TContainer.Destroy called');//this line never runs 
    inherited; 
end; 

procedure Main; 
var 
    Foo : IFoo; 
begin 
    Foo := TContainer.Create; 
    Foo.Foo; 
end; 

begin 
    Main; 
    Readln; 
end. 

Se invece di utilizzare implements, a implementare l'interfaccia nella classe TImplementor poi piste destructor.

+5

"Mi manca qualcosa?" Non lo so. Ma certamente lo siamo. Hai dimenticato di includere il codice! È richiesto un programma completo che mostri il comportamento. Altrimenti dobbiamo indovinare. –

+1

hai alcuni riferimenti extra o loop di riferimento. Aggiungi sostituzioni per TFirstSecond._AddRef e TFirstSecond._Release e inserisci i punti di interruzione qui, ottieni un elenco completo di riferimenti e vedi quali non sono stati cancellati –

+0

Bene, il problema è che le tue interfacce sono delegate. Non sono sicuro perché questo causa questo comportamento. –

risposta

15

Quello che sta accadendo qui è che chiami TContainer.Create e crei un'istanza in un oggetto. Ma poi assegni quell'istanza a un riferimento all'interfaccia, la variabile globale Foo. Poiché tale variabile è di tipo IFoo, la delega dell'interfaccia indica che l'oggetto di implementazione è l'istanza di TFooImpl e non l'istanza di TContainer.

Quindi niente prende mai un riferimento all'istanza di TContainer, il suo conteggio di riferimenti non viene mai aumentato e quindi non viene mai distrutto.

Non penso che ci sia un modo molto semplice per aggirare questo. Potresti essere in grado di utilizzare TAggregatedObject ma potrebbe non risolvere il tuo problema. Ti costringerebbe a dichiarare TContainer.FFoo di tipo TFooImpl che immagino tu non voglia fare. In ogni caso, ecco come appare rifusione in questo modo:

program SO16210993_TAggregatedObject; 

{$APPTYPE CONSOLE} 

type 
    IFoo = interface 
    procedure Foo; 
    end; 

    TFooImpl = class(TAggregatedObject, IFoo) 
    procedure Foo; 
    end; 

    TContainer = class(TInterfacedObject, IFoo) 
    private 
    FFoo: TFooImpl; 
    function GetFoo: IFoo; 
    public 
    destructor Destroy; override; 
    property Foo: IFoo read GetFoo implements IFoo; 
    end; 

procedure TFooImpl.Foo; 
begin 
    Writeln('TFooImpl.Foo called'); 
end; 

destructor TContainer.Destroy; 
begin 
    Writeln('TContainer.Destroy called');//this line does run 
    FFoo.Free; 
    inherited; 
end; 

function TContainer.GetFoo: IFoo; 
begin 
    if not Assigned(FFoo) then 
    FFoo := TFooImpl.Create(Self); 
    Result := FFoo; 
end; 

procedure Main; 
var 
    Foo : IFoo; 
begin 
    Foo := TContainer.Create; 
    Foo.Foo; 
end; 

begin 
    Main; 
    Readln; 
end. 

Il documentation vuol parlare di questo:

La classe si utilizza per implementare l'interfaccia delegato dovrebbe derivare da TAggregationObject.

Inizialmente non sono riuscito a trovare alcuna documentazione per questo TAggregationObject. E alla fine ho capito che in realtà si chiama TAggregatedObject ed è documented.

TAggregatedObject fornisce la funzionalità di un oggetto interno di un aggregato implementando metodi IInterface delegare alla controllo IInterface.

Un oggetto aggregato è un oggetto composto da diversi oggetti interfacciati . Ogni oggetto implementa il proprio comportamento e le proprie interfacce, ma tutti gli oggetti condividono lo stesso conteggio dei riferimenti, che è quello dell'oggetto controller . Nel modello contenitore, il controller è l'oggetto contenitore .

TAggregatedObject non supporta le interfacce. Tuttavia, poiché è tipico di un aggregato, implementa i metodi di IInterface, che vengono utilizzati dagli oggetti che discendono da esso. TAggregatedObject, pertanto, funge da base per le classi che implementano le interfacce per creare oggetti che fanno parte di un aggregato .

TAggregatedObject viene utilizzato come base per le classi che creano oggetti contenuti e oggetti di connessione.L'utilizzo di TAggregatedObject garantisce che le chiamate vengano delegate all'Interface di controllo dell'aggregato.

Il IInterface di controllo è specificato nel costruttore per TAggregatedObject ed è indicato dalla proprietà Controller.

Inoltre c'è questa dai commenti del codice sorgente:

TAggregatedObject e TContainedObject sono classi base adatti per gli oggetti interfacciati destinati ad essere aggregate o contenuta in un oggetto esterno controllo . Quando si utilizza la sintassi "implements" su una proprietà di interfaccia in una dichiarazione di classe dell'oggetto esterno, utilizzare questi tipi per implementare l'oggetto interno.

Le interfacce implementate da oggetti aggregati per conto del controller non devono essere distinguibili dalle altre interfacce fornite dal controller. Gli oggetti aggregati non devono mantenere il numero di riferimento - devono avere la stessa durata del controller . Per ottenere ciò, gli oggetti aggregati riflettono i metodi di conteggio dei riferimenti sul controller.

TAggregatedObject riflette semplicemente le chiamate di QueryInterface al suo controller . Da tale oggetto aggregato, è possibile ottenere qualsiasi interfaccia supportata dal controller e solo le interfacce supportate dal controller . Ciò è utile per l'implementazione di una classe del controller che utilizza uno o più oggetti interni per implementare le interfacce dichiarate sulla classe controller. Aggregation promuove la condivisione dell'implementazione attraverso la gerarchia degli oggetti.

TAggregatedObject è ciò che la maggior parte degli oggetti aggregati deve ereditare da , soprattutto se utilizzato in combinazione con la sintassi "implements" .

+0

@FabricioAraujo Ho trovato i documenti alla fine. C'era un errore di battitura !! –

+0

Sono stato indotto in errore dagli innumerevoli esempi che ho trovato altrove. Ha perfettamente senso che il conteggio dei riferimenti debba aver luogo da qualche parte. Grazie per aver risposto – Gryffe

+0

Sei il benvenuto. È stata un'esperienza di apprendimento interessante per me! –

Problemi correlati