在Delphi中创建和销毁对象

时间:2014-12-10 14:26:09

标签: delphi

我是Delphi的新手,我正在努力更好地理解对象的创建/释放,因为我已经习惯了.NET的奢侈品。我有两个具体问题:

  1. 我们假设我正在设置如下的TDataSource。在.NET中,我不会像adoQuery.Free那样明确地销毁对象。但我假设使用Delphi我需要释放这些对象。但是,通过销毁adoQuery,我也将数据集设置为null。通过这种方式,adoQuery只是函数的本地范围变量,只有从函数中重新调用datsource。因此,我怎样才能最好地处理这个问题?

    dataSrc := TDataSource.Create(nil);
    dataSrc.DataSet := adoQuery;
    dataSrc.Enabled := true;
    { adoQuery.Free; }
    cnt := DataSrc.DataSet.RecordCount;
    
  2. 从函数返回变量时,我一直在阅读几条建议,最好的办法是在调用者中创建变量并将其传递给子例程。因此,函数的签名看起来像:

    AdoConnectionManager.GetResult(query : String; dataSrc: TDataSource) : TDataSource;
    Result := dataSrc;
    
  3. 这对我来说没什么吸引力。我更喜欢在子例程中创建一个新变量,然后返回给调用者。但是,这是我从未真正担心的.NET GC,在这里我必须明确销毁变量,对吧?

    谢谢!

3 个答案:

答案 0 :(得分:2)

你问了两个问题。一个涉及这些数据库类,我将忽略该问题,因为我对这些类一无所知。相反,我会回答其他问题。请注意,这种答案就是为什么网站政策可以一次询问一个问题。

关于返回新对象的函数,这当然是可行的。但是,让调用者提供对象有时更灵活。这允许它们重用实例,或者提供从基类派生的对象。一个典型的例子是填充TStrings实例的函数。

在这种情况下,您可能使用过程而不是函数。它可能看起来像这样:

procedure PopulateList(List: TMyList);

如果你想要一个函数来返回一个新的实例,那么就像这样做:

function CreateAndPopulateList: TMyList;
begin
  Result := TMyList.Create;
  try
    // code to populate Result goes here, and may raise exceptions
  except
    Result.Free; // in case of exceptions, we must destroy the instance to avoid leaks
    raise;
  end;
end;

注意命名。我使用 create 来向调用者暗示创建了一个新实例。调用代码如下所示:

List := CreateAndPopulateList;
try
  // do stuff with list
finally
  List.Free;
end;

这种模式是标准的对象创建模式。所以你就像使用构造函数一样使用CreateAndPopulateList

答案 1 :(得分:1)

这里还应该提到,Delphi还提供了Reference-Counting(但与.NET不同)。

Delphi中对Reference-Counting的简短解释:
与其他语言不同,Delphi中的引用计数仅可通过使用接口来实现。此外,没有Garbage-Collector:当Referencecount达到0时,引用计数的Object会立即被销毁。

因此,作为Delphi开发人员,有以下“全局”规则用于销毁实例:
- 只要声明为ClassType(例如var m:TMyClass),手动销毁对象 - 只要声明为InterfaceType(例如var m:IMyClass),就不会手动销毁对象

答案 2 :(得分:0)

使用Delphi创建对象时,您应该决定如何释放它。有几种方法:

  1. 您可以手动免费使用
  2. 可与其所有者一起释放
  3. 它可以作为TObjectList或类似容器
  4. 的一部分释放
  5. 它可以被释放,因为它的接口和参考计数器变为零
  6. 依旧......
  7. 关于第一个问题:你应该明白,用Delphi对象变量是一个指向对象的指针。离开函数时,您可以丢失本地范围(指针)变量,但不会损害对象本身。例如,您可以执行以下操作:

    function GetDataSource: TDataSource;
    var Query: TADOQuery;
    begin
      Result := TDataSource.Create(nil);
      Query := TADOQuery.Create(Result);
      Query.SQL.Text := ' ... ';
      Result.DataSet := Query;
    end;
    

    它会通过后台查询为您提供所需的数据源。当您释放此数据源时,也将释放查询。

    关于第二个问题:返回对象的内部函数创建是一种常规做法,是良好设计的一部分。是的,你应该决定谁将释放这个对象以及如何释放。你可以使用很多策略,这里没有银弹。例如,您可以决定添加参数'数据源的所有者'在上面运作并以这种方式控制它的生命。