Delphi: Da quando i riferimenti all'interfaccia non vengono più rilasciati alla fine di un blocco con?
-
22-07-2019 - |
Domanda
Di recente mi sono imbattuto in un problema causato da un codice molto vecchio che ho scritto che ovviamente presupponeva che i riferimenti all'interfaccia utilizzati in un'istruzione con
sarebbero stati rilasciati non appena con
-block is left - un po 'come un implicito
try-finally
-block (simile al di C # usando
-statement se ho capito bene).
Apparentemente (in Delphi 2009) questo non è (non più?) il caso. Qualcuno sa quando è successo? O il mio codice era semplicemente sbagliato all'inizio?
Per chiarire, ecco un esempio semplificato:
type
IMyIntf = interface;
TSomeObject = class(TInterfacedObject, IMyIntf)
protected
constructor Create; override; // creates some sort of context
destructor Destroy; override; // cleans up the context created in Create
public
class function GetMyIntf: IMyIntf; //a factory method, calling the constructor
end;
procedure TestIt;
begin
DoSomething;
with (TSomeObject.GetMyIntf) do
begin
DoStuff;
DoMoreStuff;
end; // <- expected: TSomeObject gets destroyed because its ref.count is decreased to 0
DoSomethingElse;
end; // <- this is where TSomeObject.Destroy actually gets called
Ogni volta che qualcuno ha iniziato il vecchio " con
è male " argomento questo è sempre stato l'unico esempio che avevo in mente che mi ha fatto andare avanti "Sì, ma ..." Sembra che mi sia sbagliato ... Qualcuno può confermare?
Soluzione
Il con
parola preservata in Pascal / Delphi viene utilizzato solo per accedere facilmente ai membri di record o oggetti / classi (cioè per non menzionare il nome del record / oggetto / classe). È molto diverso dal record
, per semplificare la chiamata del codice a molti membri dei dati (all'epoca semplicemente chiamati "campi").
Per riassumere, con
non ha nulla a che fare con la garbage collection, il rilascio di memoria o la distruzione di istanze di oggetti. Gli oggetti costruiti nell'intestazione con
avrebbero potuto essere inizializzati in una riga di codice separata prima, è lo stesso.
Altri suggerimenti
Questo comportamento WITH non è mai cambiato. Per raggiungere il comportamento previsto, puoi modificare il codice in questo modo:
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
oppure puoi farlo nella procedura:
procedure TestIt;
procedure DoAllStuff;
var
myIntf: IMyIntf;
begin
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
end; // <- here is where TSomeObject.Destroy called
begin
DoSomething;
DoAllStuff;
DoSomethingElse;
end;