program Foo;
uses
FastMM, // MUST be first but won't bring any of 'my' units in, so this is OK
SysUtils, // These too are fine coming next because again they don't
Forms, // reference 'my' units
MyInitUnit, // <- This is where it is important to list 'my' guaranteed first/earliest
// initialisated unit of all 'my' units
MyFirstAppUnit, // And now the rest ...
etc;
unit InitFirst;
interface
uses Classes;
procedure _DoInitialisation();
implementation
var
_blInitialised: Boolean;
procedure _DoInitialisation();
begin
if(not _blInitialised) then
begin
// initialisation code goes here
_blInitialised:=True;
end;
end;
initialization
_DoInitialisation();
end.
字符串 和
unit InitSecond;
interface
uses Classes;
procedure _DoInitialisation();
implementation
uses InitFirst;
var
_blInitialised: Boolean;
procedure _DoInitialisation();
begin
if(not _blInitialised) then
begin
InitFirst._DoInitialisation();
// initialisation code goes here
_blInitialised:=True;
end;
end;
initialization
_DoInitialisation();
end.
3条答案
按热度按时间2eafrhcq1#
简单来说,初始化部分是按照
uses
子句中单元的引入顺序执行的。但是,由于单元的初始化只有在单元本身引用的任何单元初始化之后才执行 *(它们还没有初始化),因此它比这稍微复杂一点。即:
个字符
然后,装置初始化顺序为:
型
这是因为
Unit1
引入了Unit3
,所以即使Unit1
在dpr使用中列在第一位,Unit3
实际上首先初始化,然后是Unit1
的初始化。如果你记得
initialization
部分出现在单元中任何uses
子句之后,这是有意义的。因此,绝对确保任何一个单元在 any other之前被初始化的唯一方法是将其首先列在DPR
uses
子句中,并且该单元不依赖于任何其他单元(除非这些单元不依赖于或干扰正在执行的初始化)。当然,它不一定是 * 严格 * 第一。例如,如果您正在使用替换内存管理器,(例如FastMM),那么这绝对需要是你的dpr
uses
子句中列出的第一个单元。你只需要确保你需要在任何其他单元之前初始化的单元。(你的单位)然后在任何其他单位之前列出,这可能会带来你的其他单位:型
当然,如果你希望首先初始化的单元确实需要在 * 任何 * 其他单元之前初始化,包括RTL单元(与FastMM等需要的方式相同),那么你需要在dpr
uses
列表中通过更早地声明你的单元来反映这一点。x7yiwoj42#
初始化部分按照单元在
uses
子句中出现的顺序执行。因此,您可以通过在
uses
列表中向上移动单元来强制单元首先初始化。cig3rfwq3#
不幸的是, Delphi 的文档是误导性的。从我自己的研究中,我发现单元并不总是按照它们在uses子句中引用的顺序初始化。如果你对我的发现不感兴趣,跳过下一段。
使用SysInternals的实用程序ProcMon并监视构建 Delphi 代码的过程,我可以看到单元文件何时打开,以及DCU文件何时写入。似乎单元文件是按照uses子句中引用它们的顺序打开的,但编译后的DCU可能会以不同的顺序写入。通过将断点放入初始化单元的部分我已经确认了它们是按照DCU写入磁盘的顺序调用的,而不是按照单元被引用的顺序。对于简单的情况,这两种顺序可以是等同的,但是,初始化代码总是按照unit子句中引用unit的顺序调用,这肯定是不正确的。
如何强制初始化订单
当单元需要以特定的顺序初始化时,我采用的方法是在每个需要初始化的单元中使用一个公共方法。该方法在
initialization
部分中被调用。对于每个单元,都有一个单元级(私有)变量,用于指示初始化是否已运行。(对于简单的情况,布尔值就足够了,对于更复杂的情况,你可能会创建一个初始化对象,你可以使用一个指向它的指针)。然后在每个模块中,你检查你是否已经初始化,如果没有,你调用所有其他你需要在你之前初始化的单元的初始化,然后做你自己的初始化。
所以,在你使用简单布尔值的情况下,你可能有:
字符串
和
型