【问题标题】:How to avoid using inc-files for code with Delphi如何避免在 Delphi 中对代码使用 inc 文件
【发布时间】:2018-12-30 17:52:21
【问题描述】:

我使用 Bold for Delphi 作为 ORM 框架,并尝试编写代码生成如何工作以更好地理解我的问题。存储在 bld 文件中的模型用作为模型中的类生成类定义的源。

所以从头开始生成一个名为 BusinessClasses.pas 的文件。 结构是这样的:

unit BusinessClasses;

{$DEFINE BusinessClasses_unitheader}
{$INCLUDE BusinessClasses_Interface.inc}

{$INCLUDE AmObject.inc}
{$INCLUDE Quantity.inc}
{$INCLUDE Distance.inc}
// etc. My source have about 80 inc-files with code

const
  BoldMemberAssertInvalidObjectType: string = 'Object of singlelink (%s.%s) is of wrong type (is %s, should be %s)';

{ TBusinessClassesRoot 
  All classes in model inherit from TBusinessClassesRoot.
  Following is base methods that can be used everywhere}

procedure TBusinessClassesRootList.Add(NewObject: TBusinessClassesRoot);
begin
  if Assigned(NewObject) then
    AddElement(NewObject);
end;

function TBusinessClassesRootList.IndexOf(anObject: TBusinessClassesRoot): Integer;
begin
  result := IndexOfElement(anObject);
end;

function TVehicle._GetRegNo: String;
begin
  Result := M_RegNo.AsString;
end;

procedure TVehicle._SetRegNo(const NewValue: String);
begin
  M_RegNo.AsString := NewValue;
end;

// So all basic methods that Get and Set attributes for all classes is here.
// In my case it means a big file about 83000 LOC.

BusinessClasses_Interface.inc 中的代码如下所示:

{$IFNDEF BusinessClasses_Interface.inc}
{$DEFINE BusinessClasses_Interface.inc}

{$IFNDEF BusinessClasses_unitheader}
unit BusinessClasses;
{$ENDIF}

interface

uses
  // interface uses
  {$INCLUDE Attracs_Interface_Uses.inc} ,  
  // other
  Classes,
  // more uses follow...

type
  { forward declarations of all classes }

  TBusinessClassesRoot = class;
  TBusinessClassesRootList = class;
  TaccountProperty_TransportAccountProperty = class;
  TaccountProperty_TransportAccountPropertyList = class;
// A lot of forward declarations follow....

  TBusinessClassesRoot = class(TBoldObject)
  private
  protected
  public
  end;

  TaccountProperty_TransportAccountProperty = class(TBusinessClassesRoot)
  private
    function _GetaccountProperty: TTransportAccountProperty;
    function _Get_M_accountProperty: TBoldObjectReference;
  protected
  public
    property M_accountProperty: TBoldObjectReference read _Get_M_accountProperty;
    property accountProperty: TTransportAccountProperty read _GetaccountProperty;
  end;

// More class declarations follow
// File size is about 35000 LOC

所以 BusinessClasses_Interface.inc 和 BusinessClasses.pas 是从头开始生成的 而像 AmObject.inc 这样的带有真实代码的 inc 文件则由开发人员维护。

从 D7 开始就一直这样工作。但也有一些缺点。

  • Codeinsight 在 inc 文件中无法正常工作
  • 许多分析 Delphi 代码的工具不适用于 inc 文件
  • 由于某些原因,有时项目无法编译,因为 BusinessClasses_Interface.inc 被 bds.exe 锁定。 有时重启是唯一的选择,但它是随机的。

所以我最初的想法是将所有 inc 文件转换为标准的 pas 文件。对代码的引用应该通过 uses 而不是 $INCLUDE inc-file。然后我发现为什么选择了这种将代码存储在 inc 文件中的奇怪解决方案。模型中的两个类可以相互关联。这意味着A类引用了B类。B类引用了A类。这必须有效。类前向声明​​用于此。 Delphi 编译器似乎需要这个。

来自http://docwiki.embarcadero.com/RADStudio/Rio/en/Classes_and_Objects_(Delphi)#Forward_Declarations_and_Mutually_Dependent_Classes

前向声明必须由同一类型声明部分中同一类的定义声明来解析。换句话说,在前向声明和它的定义声明之间,除了其他类型声明之外,什么都不会发生。

所以 Delphi 10.3 Rio 的工作方式与旧 D7 完全相同。

好的,现在我的问题终于来了:)

除了 Bold 之外,我还没有看到任何其他项目使用 inc 文件来存储代码。 是否有任何其他技巧或解决方案可以达到相同的结果?

【问题讨论】:

  • FPC 使用 .inc 文件。 yunqa 的整个产品线(DIContainers、DISQLite3 等)也是如此。
  • 但是这些项目是否使用 inc 文件作为代码?我只看到它被用于常量和 $DEFINE。

标签: class delphi


【解决方案1】:

最简单的解决方案是在生成包含文件和单元文件后运行 pascal 预处理器,以将包含文件合并到单元中。 这是一个: http://clootie.narod.ru/delphi/download_utils.html#ppp

所以所有的包含文件都会在单元内结束。可以删除包含文件以避免混淆。

【讨论】:

  • +1 链接。我也是这么想的。但是生成的文件会很大! Delphi IDE 无法加载和编辑这么大的文件。
【解决方案2】:

我现在相信我有办法解决这个问题。我认为罪魁祸首是类之间可以直接访问。所以A类知道B类等。 所以接口可能是解决方案。

不幸的是,这对我来说意味着很多工作,因为模型中的所有引用都需要更改。代码生成也需要生成接口而不是直接链接。但最需要的工作是 Bold 框架本身,因为它现在不支持接口。

但这个小样本至少有效:

单元A

unit TestA;

interface

uses
  TestInterfaces;

type
  TTestA = class
    M_TestB: ITestB;
  end;

implementation

end.

单元B

unit TestB;

interface

uses
  TestInterfaces;

type
  TTestB = class
    M_TestA: ITestA;
  end;

implementation

end.

接口

unit TestInterfaces;

interface

type
  ITestA = interface
    ['{5DE20444-241E-4F59-9B7F-96A76BA3DDFF}']
  end;

  ITestB = interface
    ['{40C19A93-C816-4D1E-9C74-6B710D6974BF}']
  end;

implementation

end.

【讨论】:

    猜你喜欢
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多