Delphi: Seit wann sind Interface-Referenzen nicht mehr am Ende eines mit-Block freigegeben?
-
22-07-2019 - |
Frage
Ich stolperte vor kurzem über ein Problem von einigen sehr alten Code verursacht ich schrieb, die offensichtlich, dass die Interface-Referenzen in einer with
Anweisung verwendet wurde angenommen würde, sobald der with
-Block bleibt freigegeben werden - ein bisschen wie eine implizite try-finally
-Block (ähnlich wie C # 's using
-Anweisung, wenn ich das richtig verstanden).
Anscheinend (in Delphi 2009) ist dies nicht (mehr?) Der Fall ist. Weiß jemand, wenn dies geschehen ist? Oder war mein Code einfach falsch zu beginnen?
Um zu klären, ist hier ein vereinfachtes Beispiel:
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
Jedes Mal, wenn jemand die alte „with
ist böse“ Argument war immer das ein Beispiel begann ich im Sinn hatte, die mich gehen gehalten „Ja, aber ...“. Scheint, wie ich falsch war ... jemand bestätigen kann?
Lösung
Die with
erhaltene Wort in Pascal / Delphi ist nur für die leicht Zugriff auf die Mitglieder der Datensätze oder Objekte / Klassen (das heißt, um nicht zu erwähnen, den Datensatz des / Objekt / der Klasse Name) verwendet. Es ist sehr verschieden von der C # with
, der Garbage Collection bezieht. Es hat sich in der Sprache Pascal existierte seit dem Tag records
geboren wurden, Code Aufruf zu viele Datenelemente zu vereinfachen (damals einfach „Felder“ genannt).
Um es zusammenzufassen, hat with
nichts mit Garbage Collection, der Freisetzung von Speicher oder Zerstörung von Objektinstanzen zu tun. Objekte, die vor initialisiert, in einem separaten Codezeile könnte das gleiche, es ist an der with
Header konstruiert sind gerade.
Andere Tipps
Das MIT-Verhalten hat sich nie geändert. Um Ihr erwartetes Verhalten erreichen Sie können den Code auf diese Weise ändern:
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
oder Sie können es in der Prozedur tun:
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;