Delphi 将_记录集结果与TADOConnection.Execute函数一起使用

Delphi 将_记录集结果与TADOConnection.Execute函数一起使用,delphi,delphi-7,Delphi,Delphi 7,函数返回一个_记录集 为了简单起见,我目前使用此代码1: 我知道记录集从来都不是空的,所以不用担心BOF 现在我可以用一个局部记录集变量2这样写它 多一点代码 现在我的问题是:由于_记录集是由Execute函数返回的接口变量,如果我没有使用局部rs变量1,它会被正确释放吗?使用我的简化代码1安全吗?这里会有引用计数问题吗 我想了解一些关于这个问题的见解 编辑:我的问题针对具体案例: V := ADOConnection1.Execute(SQL).Fields[0].Value 当我没有对_记

函数返回一个_记录集

为了简单起见,我目前使用此代码1:

我知道记录集从来都不是空的,所以不用担心BOF

现在我可以用一个局部记录集变量2这样写它

多一点代码

现在我的问题是:由于_记录集是由Execute函数返回的接口变量,如果我没有使用局部rs变量1,它会被正确释放吗?使用我的简化代码1安全吗?这里会有引用计数问题吗

我想了解一些关于这个问题的见解

编辑:我的问题针对具体案例:

V := ADOConnection1.Execute(SQL).Fields[0].Value

当我没有对_记录集的局部变量引用时。

试试这个:创建一个包含单行的过程

  V := AdoConnection1.Execute(Sql).Fields[0].Value;
,在其上放置断点运行应用程序并查看反汇编。你会在排队前看到的

jmp @HandleFinally
有三个电话要打

call @IntfClear
这是编译器为了执行语句而必须访问的三个接口,即

AdoConnection1.Execute返回的记录集接口, 该记录集的字段接口,以及 通过字段[0]获得的特定字段接口。 因此,它在执行源语句后自动生成释放这些接口所需的代码

以下是一个不完美的类比,但它的分解更容易理解;它演示了编译器自动生成的代码,以处理终结接口

给定

Button1Click的CPU反汇编如下所示

红色箭头所示的线是清除接口的位置,不管源代码如何 没有做任何明确的事情来做到这一点。将断点放在

inherited
在TMyClass.Destroy中,你会发现它也会被调用,尽管 源代码没有显式地调用它

正如我所说,上面的类比并不完美。一件有趣的事情是,从使用with construct替代品的角度来看,这很可怕

procedure TForm1.Button1Click(Sender: TObject);
begin
  with IMyInterface(TMyClass.Create) do
    Caption := IntToStr(GetValue);
end;
如果不使用显式局部变量,编译器将生成与反汇编所示完全相同的代码


当然,q中的情况稍有不同,因为分配给recordset对象的内存位于Ado COM接口的另一侧,因此除了编译器将生成代码以调用接口上的_Release外,无法控制该内存是否被正确取消分配。

是,它将被发布。如果您存储该引用并将其存储在执行查询的方法范围之外,则不会发生这种情况。@TLama,您能证明它吗?我这样问是因为我记得读到过关于创建接口但未分配给变量的问题,这些问题与引用计数有关。我错了,@TLama所说的是正确的,但如果您有疑问,只需在某行代码中设置一个断点并打开CPU窗口。然后一步一步地运行代码。你会看到调用方法AddRef和Release的精确时刻。我想你不明白这个问题。我做了一个编辑。事实上,恕我直言,我想我确实理解了你的要求,只是想不出一个直接说明的方法。无论如何,请参见我的编辑,它添加了一个没有显式局部变量的替代方案。在回答另一个关于调用_Release的评论时,并不保证内存被释放,事实上不保证,但在考虑的情况下,内存是由实现接口的Ado对象分配的,除了遵循_AddRef/_Release使用规则外,Delphi无法对其进行控制。关于内存:状态在关闭对象后,在Visual Basic中将对象变量设置为Nothing。我担心的是关上物体后的感觉。我会明确地称之为close,而不是依赖于发布only@Jasper:您为什么不发布一个问题,大意是如果我使用实现它的Delphi对象实例化一个接口,那么在我使用完该对象后是否需要对其调用Free?我肯定你会被答案轰炸,答案说当然不会,因为编译器会处理这个问题。这是人们在Delphi中使用接口的原因之一,即自动生命周期管理。
type
  IMyInterface = interface
    function GetValue : Integer;
  end;

  TMyClass = class(TInterfacedObject, IMyInterface)
    function GetValue : Integer;
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    [...]
    procedure Button1Click(Sender: TObject);
  end;

destructor TMyClass.Destroy;
begin
  inherited;
end;

function TMyClass.GetValue: Integer;
begin
  Result := 1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I : IMyInterface;
begin
  I := TMyClass.Create;
  Caption := IntToStr(I.GetValue);
end;
inherited
procedure TForm1.Button1Click(Sender: TObject);
begin
  with IMyInterface(TMyClass.Create) do
    Caption := IntToStr(GetValue);
end;