Delphi: ¿Desde cuándo las referencias de interfaz ya no se publican al final de un bloque?
-
22-07-2019 - |
Pregunta
Recientemente me topé con un problema causado por un código muy antiguo que escribí, que obviamente suponía que las referencias de interfaz utilizadas en una declaración with
se liberarían tan pronto como con
-block se deja - algo así como un implícito try-finally
-block (similar a la declaración de de C # usando
si entendí correctamente).
Aparentemente (en Delphi 2009) este no es el caso (¿ya no?). ¿Alguien sabe cuándo sucedió esto? ¿O fue mi código simplemente incorrecto para empezar?
Para aclarar, aquí hay un ejemplo simplificado:
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
Cada vez que alguien comienza el viejo " con
es malo " argumento este fue siempre el único ejemplo que tenía en mente que me mantuvo en marcha "Sí, pero ...". Parece que me equivoqué ... ¿Alguien puede confirmar?
Solución
La palabra preservada with
en Pascal / Delphi solo se usa para acceder fácilmente a los miembros de registros u objetos / clases (es decir, para no mencionar el nombre del registro / objeto / clase). Es muy diferente del C # con
que se relaciona con la recolección de basura. Ha existido en el lenguaje Pascal desde el día en que nacieron los records
, para simplificar la llamada de código a muchos miembros de datos (en ese entonces simplemente se llamaban "campos").
Para resumir, with
no tiene nada que ver con la recolección de basura, liberación de memoria o destrucción de instancias de objetos. Los objetos que se construyen en el encabezado with
podrían haberse inicializado en una línea de código separada antes, es lo mismo.
Otros consejos
Este comportamiento WITH nunca ha cambiado. Para alcanzar su comportamiento esperado, puede cambiar su código de esta manera:
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
o puede hacerlo en el procedimiento:
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;