【问题标题】:Difference between adding a unit to the interface or the implementation section将单元添加到接口或实现部分之间的区别
【发布时间】:2009-02-09 14:57:27
【问题描述】:

如果我有一个充满常量的单元,比如...

unit AConsts;
interface
const
   Const1 : WideString = 'Const1';
   Const2 : WideString = 'Const2';
   Const3 : WideString = 'Const3';
   Const4 = 100;
   Const5 = 100;
implementation
end.

我想从另一个单位使用这个单位,有什么区别...

unit AUnit;
interface
uses 
  AConsts;
Implementation
end.

unit AUnit;
interface
implementation
uses
  AConsts;
end.

?

问题不在于范围、避免循环引用等。而是关于已编译应用程序的差异。

如果UnitAUnitBUnitC都使用AConsts,那么在编译的应用程序(假设AConsts单元中的常量和其他代码之间没有名称冲突)之间的@ 987654329@ 其中UnitAUnitBUnitCinterface 部分都有AConstsApp2 其中UnitAUnitBUnitC 都有@ 实施部分中的 987654338@。

【问题讨论】:

  • 也许我有点老派,但我认为在界面中你应该只使用你的声明所需的单元,这些单元将在单元外可用,因此在界面中。您应该将所有其余部分付诸实施。 AFAIK,在古代,这有助于编译器速度和生成的 exe 大小,但最近的版本可以更好地处理。但是,它仍然是一种整洁的方式。

标签: delphi


【解决方案1】:

不同之处在于您可以在哪里引用AConsts 在其界面部分中的内容。在第一个AUnit 中,您可以使用Const4that 接口部分声明一个固定大小的数组。你不能在第二个AUnit 中这样做,因为Const4 不在范围内。

如果你不小心,它可以对编译的程序产生影响。假设我们有另一个单元,声明了一个名为Const4的常量:

unit BConsts;
interface
const
  Const4 = 50;
implementation
end.

现在我们在UnitA 中定义一个数组,如下所示:

unit AUnit
interface
uses BConsts;
var
  data: array[0..Pred(Const4)] of Integer;
implementation
uses AConsts;
procedure Work;
var
  i: Integer;
begin
  for i := 0 to Const4 - 1 do begin
    data[i] := 8;
  end;
end;
end.

该代码将写入数组末尾之外,因为接口部分范围内的Const4 与实现部分中使用的Const4 不同。这不会经常发生在常量中。它通常只发生在两个标识符上,WindowsSysUtils 中定义的 FindClose 函数和 GraphicsWindows 中定义的 TBitmap。在这两种情况下,编译器会告诉您您做错了什么,尽管它不会准确地告诉您您使用了具有两种不同含义的标识符。您可以通过限定标识符来解决问题:

for i := 0 to BConsts.Const4 - 1 do
  data[i] := 8;

如果上述所有预防措施都得到解决,那么您的程序可以正确编译和运行,那么在哪里使用单位就没有区别了。在您使用 App1 和 App2 的示例中,这两个程序将是相同的。它们不会完全相同——编译器会以不同的顺序处理事物,因此可能会将事物放在不同的位置——但这不会影响程序的执行。

【讨论】:

    【解决方案2】:

    我把所有引用都放在实现部分,只把那些单元名放在我必须的接口中。

    不过,我喜欢尽可能地限制所有内容的范围,而本政策就是以此为依据的。

    【讨论】:

      【解决方案3】:

      IDE 还使用您声明用途的方式来确定需要编译的内容。

      如果您的接口部分使用 UnitA 而您的实现部分使用 UnitB,那么如果单元 B 需要重新编译,则您的单元不会,但如果 unitA 发生更改,则您的单元将需要重新编译。

      这是 Delphis 超快速构建速度的秘诀之一。

      至于您完成的可执行文件,我希望无论您在哪里放置声明,它都会产生相同的大小(链接器很聪明,只链接您的应用程序实际使用的方法等),但各种文件的实际位置如果单位声明的顺序发生变化,来源几乎肯定会发生变化。

      【讨论】:

        【解决方案4】:

        界面中uses语句中的项在整个单元中可见。

        实现中uses语句中的项仅在实现部分可见。

        例子:

        unit A;
        interface
        const 
          cA = 1;
        ..
        
        
        unit B;
        interface
        const 
          cB = 1;
        ..
        
        
        
        unit C;
        interface
        uses
          A;
        const 
          cC1 = cA;
          cC2 = cB; // Error
        
        implementation
        uses
          B;
        const
          cC3 = cA;
          cC4 = cB;
        
        end.
        

        如果实施部分中至少包含一个单元,则可以创建相互依赖的单元:

        unit A;
        interface
        implementation
        uses
          B;
        end.
        
        
        unit B;
        interface
        implementation
        uses
          A;
        end.
        

        如果两者都在接口部分使用,则不会编译/链接。

        【讨论】:

          【解决方案5】:

          除非我需要处理循环引用的问题,否则我遵循将所有内容都放在接口部分的规则。这有助于带来一点清晰。 Delphi 中的一些向导和“文件>使用单元...”对话框将单元放在实现部分。

          除了 Rob Kennedy 强调的范围界定陷阱之外,这无关紧要。制定你的标准并坚持下去。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-10-24
            • 1970-01-01
            • 1970-01-01
            • 2014-08-01
            • 2022-10-21
            • 2016-12-05
            • 2011-03-23
            • 2010-10-17
            相关资源
            最近更新 更多