Delphi:with-blockの終わりにインターフェイス参照が解放されなくなるのはいつですか?
-
22-07-2019 - |
質問
最近、私が書いた非常に古いコードに起因する問題につまずきました。これは、 with
ステートメントで使用されているインターフェース参照が with
-ブロックは残っています-暗黙の try-finally
-ブロックのようなものです(正しく理解している場合、C#の using
-statementに似ています)。
どうやら(Delphi 2009では)そうではありません(もはや?)。誰がこれがいつ起こったか知っていますか?または、私のコードは最初から間違っていたのですか?
明確にするために、簡単な例を示します:
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
誰かが古い&quot; with
is evil&quot;を開始したときはいつでも議論これは常に私が「はい、しかし...」を続けることを念頭に置いていた1つの例でした。私が間違っていたようです...誰でも確認できますか?
解決
Pascal / Delphiの with
で保存された単語は、レコードまたはオブジェクト/クラスのメンバーに簡単にアクセスするためにのみ使用されます(つまり、レコード/オブジェクト/クラスの名前は言うまでもありません)。ガベージコレクションに関連するC# with
とは大きく異なります。多くのデータメンバーへのコード呼び出しを単純化するために(当時は単に「フィールド」と呼ばれていました)、 records
が生まれた日からPascal言語に存在していました。
要約すると、 with
は、ガベージコレクション、メモリの解放、オブジェクトインスタンスの破棄とは関係ありません。 with
ヘッダーで構築されるオブジェクトは、以前は別のコード行で初期化されていた可能性がありますが、同じです。
他のヒント
このWITH動作は変更されていません。予想される動作に到達するには、次の方法でコードを変更できます。
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
または手順で実行できます:
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;