使用带有TADOConnection.Execute函数的_Recordset结果

时间:2015-08-17 11:28:07

标签: delphi delphi-7

TADOConnection.Execute函数返回_Recordset

我目前正在使用此代码以简化(1)

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

我知道记录集从不为空所以不用担心BOF

现在我可以用本地_Recordset变量(2)这样写它。

var
  rs: _Recordset; 

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

多一点代码。

现在我的问题是:由于_Recordset是Execute函数返回的接口变量,如果我不使用本地rs 变量(1)?正在使用我的简化代码(1)安全,这里是否存在引用计数问题?

我想就此问题获得一些见解。

编辑:我的问题仅针对此案:

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

我没有_Recordset的本地变量引用。

1 个答案:

答案 0 :(得分:4)

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

  V := AdoConnection1.Execute(Sql).Fields[0].Value;

,在它上面放置一个断点来运行应用程序并查看反汇编。你会在行

之前看到它
jmp @HandleFinally

有三次调用

call @IntfClear

编译器释放它必须访问的三个接口才能执行该语句,即

  • AdoConnection1.Execute(),
  • 返回的RecordSet接口
  • 该RecordSet的Fields接口和
  • 通过Fields [0]获得的特定Field接口。

因此,它在执行源语句后自动生成释放这些接口所需的代码。

以下是一个不完美的类比,但它的拆卸更容易遵循;它说明了编译器自动生成的代码,用于处理最终化接口。

鉴于

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;

Button1Click的CPU反汇编看起来像这样

disassembly

,红色箭头表示尽管源代码清除了界面 没有做任何明确的事情来做这件事。

上设一个断点
inherited
在TMyClass.Destroy中的

你会发现它也会被调用,尽管如此 源代码没有明确地调用它。

就像我说的,上面是一个不完美的类比。一个有趣的事情是,对于可怕的(来自使用"使用"构造)的替代

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

使用no(显式)局部变量,编译器生成完全相同的代码,如图所示的反汇编。

当然,q中的情况略有不同,因为分配给记录集对象的内存位于Ado COM接口的另一端,因此无法控制该内存是否在事实之外正确解除分配编译器将生成代码以在其接口上调用_Release。