Delphi 2010中记录与类的类方法

时间:2011-03-07 13:54:39

标签: delphi delphi-2010

我刚刚开始使用Delphi 2010 IOUtils.pas中的新单元,我发现他们将所有方法都放在Records(TFile, TPath, TDirectory)中作为类函数和过程。

在记录中而不是在类中执行此操作有什么好处吗? 在这两种情况下都不需要任何变量或实例,但我不确定在内存消耗或性能改进方面是否有任何实际好处。

4 个答案:

答案 0 :(得分:21)

记录中的类方法用于将不同的方法分组到公共名称空间中。因此,您可以为不同的目的使用类似的命名方法。有关IOUtils.pas中的示例,请查看TFile和TDirectory中提供的 Exists 函数。较旧的方法是为FileExists和DirectoryExists(实现实际调用)提供不同的函数名称。

虽然类中的类方法可以以相同的方式使用,但它们还可以有另一个目标:它们可以是虚拟的。从类变量调用,这可能导致不同的实现,具体取决于该变量的当前内容。这不适用于记录。因此,记录中的类方法始终是静态的。

答案 1 :(得分:8)

我想说的第一个问题是“为什么要将这些函数放在记录类中?”首先。

IOUtils 中使用记录方法在许多情况下在Delphi中基本上是任意的,并且部分反映了在Delphi中与其他语言无直接关系的以下约定的迷信。

在某些语言(Java和.NET?)中,不支持“第一类”功能。也就是说,程序和函数不能独立于任何容器类存在。因此,在这些语言中,如果您有功能和程序,则必须包含在类中。如果它们不对成员数据进行操作,那么很明显它们被声明为类方法,以避免构造实例只是为了调用实际上是一个classLESS函数。

TDirectory.Exists(s) TFile.Exists(s) DirectoryExists(s) FileExists的语法替代方案(S)

在Delphi中,支持第一类函数 ,因此没有真正的理由使用类或记录来区分函数,除非是为了便于开发人员编写代码时的参考和使用IDE帮助浏览可用的方法。

如果没有容器记录/类,您必须知道有一个名为“ DirectoryExists()”的函数。使用容器记录,您只需知道存在类型 TDirectory ,然后IDE(通过代码完成建议)可以显示 TDirectory 的所有“方法” operations。

然而,在Delphi中,通过支持一流功能,可以实现另一种选择。您(或者更确切地说是 IOUtils 的作者)可以选择使用现有容器 - 一个Delphi“单元”,而不是使用任意和人为的“容器”:

  unit IOUtils.Directory;

  interface

  function Exists(s): Boolean;

  unit IOUtils.File;

  interface

  function Exists(s): Boolean;

这仍然以代码完成建议的形式享受IDE支持的好处,并且还提供了支持在不同事物上运行的相同函数名称所需的命名空间分离。

这种方法的缺点(并且它是一个很大的方面)是一个单位同时使用 IOUtils.File IOUtils.Directory ,它必须符合一个或其他函数名称,以避免混淆,但这个资格可以被省略,这就是为什么它是如此危险:

  uses
    IOUtils.File,
    IOUtils.Directory;
  ..
  begin
    if Exists(s) then  // << tests existence of a directory
    ..
    if IOUtils.File.Exists(s) then  // << ensure we test for a file
    ..
    if IOUtils.Directory.Exists(s) then  // << ensure we test for a directory
  end

当然,这也可能是一个优点,如果您的单元包含仅适用于目录的代码,它将仅使用 IOUtils.Directory ,并且无需限定并重复该事实,而不是在使用条款。

当然,潜在且非常真实的危险在于,将来如果单元被扩展并随后开始使用 IOUtils.File ,那么这很容易导致任何不合格的引用上的作用域错误。 / p>

您在代码中偏好哪种方法在很大程度上取决于个人偏好以及在范围错误中发生冲突的可能性,其中您在不同实体上运行类似/同名或语义等效的函数。

出于这些原因, IOUtils 中的设计选择至少是可以理解的,可以说是一个很好的选择,你可以。

但在其他情况下,如果您所寻求的是一种将相关函数分组的方法,这些函数不会出现与类似函数混淆/碰撞的风险,那么使用人工和任意容器是多余的。函数必须驻留的单元本身可以提供您需要的所有分组行为。

至于为什么要记录而不是班级......

我怀疑在制作这些任意容器时使用记录而不是类可能会有一点静态内存的好处。我认为一个类有额外的开销,这本质上是相对较小和静态的(即每个类的开销稍高,但与它的类方法的次数无关)使用)。

答案 2 :(得分:4)

静态类方法只是一种语法糖 - 你总是可以将它们作为普通的程序/函数来实现。

如果在记录中实现了类方法,则开销较小。任何类声明都需要在内存中为类信息提供额外的结构。记录没有结构。

答案 3 :(得分:2)

IMO需要一个很好的理由来使用静态方法对类进行记录。当速度很重要时,就像TValue一样。 例如,事实证明TDirectory.CreateDirectory()只是UNC路径失败导致TPath.DriveExists()失败的UNC路径。 (D2010) 如果它是一个类,我会写一个实现我自己的TDirectory.CreateDirectoryEx()的辅助类。 由于它是一个记录,我不能从IOUtils复制一些代码或编写我自己的代码。在任何情况下,我都会使用代码冗余。 因此从可行的代码选择记录的角度来看是一个坏主意。 (我实际上仍然想知道为什么VCL团队决定不考虑可扩展性。我的意思是在这方面将VCL与DevEx的QuantumGrid进行比较。两者之间有光年)

好的,我发现你实际上可以为记录写一个帮手:

TDirectoryHelper = record helper for TDirectory

end;

但由于您无法从TDirectory

访问任何私有静态方法,因此无济于事