2011-06-03 60 views
4

我正在写一个简单的依赖注入/控制系统反转基于TDictionary持有抽象类引用及其各自的实现者类。当类注册完成该类构造函数时不会调用类构造函数

我的目标是:通过类型(显然)

  • 避免直接实例化。
  • 在dpr中包含类的单元应该足以让它注册并通过di/ioc系统进行选择和实例化。
  • 仅声明实现部分中的具体实现类。
  • 使用类构造函数而不是初始化段。

顺便说一句,我知道使用类构造函数来利用智能链接,并希望包含一个单位足以使一个类可用互相击败。我想用其他原因使用类构造函数而不是初始化部分。我想将所有的类初始化/注册代码放在一起,而不必在类构造函数和初始化部分之间进行分割。

问题

我希望类的登记进厂是在类的构造函数。不幸的是,编译器并不认为这个类是通过在它自己的类构造函数中使用它的类型而“感动”的。

当我将注册函数放入初始化部分时,编译器确实认为该类被触及并调用类​​构造函数。但是这样做打破了我在类构造函数中保留所有类初始化代码的对象。

两个问题

  • 如果编译器考虑自己的类的构造函数“触摸班”使用类或者是太大的奢望编译器做什么?
  • 有没有人有任何聪明的想法,我仍然可以实现我的目标,而不使用初始化部分?

抽象的应用程序中使用类:

TSite = class abstract (TObject) 
    function GetURL: string; virtual; abstract; 
    property URL: string read GetURL; 
end; 

TSites = class (TList<TSite>); 

TThisApplication = class abstract (TObject) 
    function Sites: TSites; virtual; abstract; 
end; 

具体的实现类(在实现部分声明!)为TThisApplication

TThisApplicationConcrete = class(TThisApplication) 
    class constructor ClassCreate; 
    strict private 
    FSites: TSites; 
    function Sites: TSites; override; 
    end; 

class constructor TThisApplicationConcrete.ClassCreate; 
begin 
    RegisterImplementorClass(TThisApplication, TThisApplicationConcrete); 
end; 

function TThisApplicationConcrete.Sites: TSites; 
var 
    SiteList: TSites; 
begin 
    if not Assigned(FSites) then begin 
    SiteList := TSites.Create; // Change to use factory 
    //RetrieveSites(SiteList); 
    FSites := SiteList; 
    end; 

    Result := FSites; 
end; 

的函数来获取TThisApplication的实例:

function ThisApplication: TThisApplication; 
var 
    ImplementorClass: TClass; 
begin 
    ImplementorClass := GetImplementorClass(TThisApplication); 
    if Assigned(ImplementorClass) then begin 
    Result := ImplementorClass.Create as TThisApplication; 
    end else begin 
    Result := nil; 
    end; 
end; 

这是目前编码在一个单独的功能,但它瓦特/可移至工厂。

完整的示例代码

如果有人想尝试,我有我的可用的测试项目,在全码:http://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip

邮编内容:全部采用

  • 4个项目相同的源文件,只有条件定义不同(这就是为什么dproj也包括在内)
  • 4源文件
  • groupproj,并与所有4个项目DSK
  • RunTestApps.cmd运行所有4个项目
  • RESULTS.TXT与我的RunTestApps.cmd
  • WriteUp.txt的运行的输出与该文本问题

请记住,在任何时候,你需要做一个“构建所有Projecs”,因为所有的DCU的和exe的是要在源代码目录否则你要面对很多的错误和/或因为EXE没有做它的名字所表示的混淆。

+0

Uwe的和Allan的答案之间千钧一发。因为类比而与Allan一起。它给了我一个我想要做的事情的生动画面,让我微笑...... – 2011-06-04 09:16:22

+0

Déjàvu:你不喜欢它,当你设计一个解决方案,它失败了,因为你做了一个隐含的假设,你甚至不知道你做了它:) – 2011-06-07 08:36:58

回答

8

这是预期的。正如Uwe指出的那样,自引用类构造函数不足以触发包含。将参考放在初始化部分将会执行这个技巧,因为它不在类本身之内。尝试自我引用一个类包含类似于试图通过拉你自己的吊带把自己拉出一个深洞。

+3

用于比喻。 – 2011-06-03 20:23:01

7

只要你不在类的任何地方使用这个类,编译器会把它作为根本不使用的类,因此不会调用类的构造函数。所以我想你必须使用初始化部分,而不是调整代码来愚弄编译器。采取务实的态度,而不是教条式的态度。无论如何,它会更具可读性。

+1

是的,我的实用主义者已经在工作压制教条主义。我想我需要外部确认。 – 2011-06-03 19:58:50

2

我认为你期望类构造函数的工作方式不同于它的设计目的。类构造函数不会在第一次创建之前被调用。 (至少不在WIN32 delphi中)。如果一个类被引用,它的类构造函数将在之前运行该单元的初始化代码。

如果您对您的类的唯一引用恰好在该类内部,那么实际上链接到您的应用程序中的任何代码都不会引用该类。因此,它的类构造函数将永远不会被调用。

我相信寄存器函数属于初始化部分。具有寄存器功能将强制类构造函数也被执行。我不明白你为什么要/要求把注册码放到类的构造函数中。

如果您想了解的方式类的构造函数/析构函数工作的详细信息,您可以通过艾伦·鲍尔阅读本相当不错的文章:

http://blogs.embarcadero.com/abauer/2009/09/04/38899