Delphi:从什么时候开始,接口引用不再在with块的末尾发布?

Delphi:从什么时候开始,接口引用不再在with块的末尾发布?,delphi,interface,delphi-2009,reference-counting,with-statement,Delphi,Interface,Delphi 2009,Reference Counting,With Statement,我最近遇到了一个由我编写的一些非常旧的代码引起的问题,该问题显然是假设with语句中使用的接口引用将在with-块离开后立即释放-有点像隐式try finally-块(类似于C#的使用-语句,如果我理解正确的话) 显然(在Delphi 2009中)情况并非如此(不再如此)。有人知道这是什么时候发生的吗?或者我的代码一开始就完全错了 为了澄清,这里有一个简化的示例: type IMyIntf = interface; TSomeObject = class(TInterfacedObjec

我最近遇到了一个由我编写的一些非常旧的代码引起的问题,该问题显然是假设
with
语句中使用的接口引用将在
with
-块离开后立即释放-有点像隐式
try finally
-块(类似于C#的
使用
-语句,如果我理解正确的话)

显然(在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
类型
IMyIntf=接口;
TSomeObject=class(TInterfacedObject,IMyIntf)
受保护的
构造函数Create;override;//创建某种上下文
析构函数Destroy;override;//清除在Create中创建的上下文
公众的
类函数GetMyIntf:IMyIntf;//一个工厂方法,调用构造函数
结束;
程序测试;
开始
剂量测定法;
使用(TSomeObject.GetMyIntf)do
开始
多斯塔夫;
多莫瑞斯图夫;

end;//Pascal/Delphi中带有
保留字的
仅用于轻松访问记录或对象/类的成员(即,为了不提及记录/对象/类的名称)。它与垃圾收集相关的C#
with
非常不同。自
记录
诞生之日起,它就存在于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; 
程序测试;
变量
myIntf:IMyIntf;
开始
剂量测定法;
myIntf:=TSomeObject.GetMyIntf
多斯塔夫;
多莫瑞斯图夫;

myIntf:=nil;//正确,创建的对象的范围是它的所有者,即本例中的过程。在上面的示例中,它应该在最后一刻被销毁。任何其他操作都是意外的,可能是D2009中更正的错误。自从在版本3中将接口引入Delphi以来,行为一直是相同的。没有修正错误。奥利弗只是忘记了事情是如何运作的。又一个“with”的例子导致意外的结果。我总是想象
with
创建一个匿名的、范围严格的局部变量,该变量只存在于
with
-块中。对于我来说,即使您无法再访问该引用,内存管理器仍然保留该引用似乎是毫无意义的……考虑到这一点(现在看来:非常不正确)从世界的角度来看,我认为当引用超出范围时,期望引用计数立即减少是完全正确的……并且澄清:我从未期望带有
-block的
会直接影响引用对象的生存期-我只期望隐含局部变量的范围限于该块,并且因此,它的引用计数将在该块结束时立即减少。不幸的是,这两个备选方案都违背了保持代码简洁的主要意图之一……而且,在第一个示例中,为了清晰起见,我将添加一个
try finally
块(虽然不是严格必要的),我也不喜欢将变量声明为“空”仅为滥用^D^D^D^D^D^D而存在的接口类型利用了接口对象的引用计数特性…我希望尽可能保持这些匿名性…但不可否认,这只是我的个人特质
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;