4

我最近偶然发现了一个由我编写的一些非常旧的代码引起的问题,该代码显然假设with语句中使用的接口引用将在with离开 -block 后立即释放 - 有点像隐式try-finally-block(类似于 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

每当有人开始旧的“with是邪恶的”论点时,这始终是我想到的一个例子,它让我继续“是的,但是......”。好像我错了...有人可以确认吗?

4

2 回答 2

17

Pascal/Delphi 中的with保留字仅用于方便地访问记录或对象/类的成员(即,为了不提及记录/对象/类的名称)。with它与与垃圾收集相关的 C# 非常不同。它从诞生之日起就存在于 Pascal 语言records中,以简化对许多数据成员的代码调用(当时简称为“字段”)。

总而言之,with与垃圾收集、内存释放或对象实例的销毁无关。在标头构造的对象with之前可能只是在单独的代码行中初始化,它是相同的。

于 2009-08-05T15:06:39.037 回答
3

这种 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; 
于 2009-08-05T18:50:54.990 回答