当类注册在该类构造函数中完成时,不会调用类构造函数 [英] Class constructor not called when class registration is done in that class constructor

查看:340
本文介绍了当类注册在该类构造函数中完成时,不会调用类构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我的目标是:

我正在写一个简单的依赖注入/反转控制系统,该控件系统基于一个带有各自的实现者类的抽象类引用的TDictionary。 p>


  • 避免按类型直接实例化(显然)。

  • 在dpr中包含一个类单元应该足够让它注册并可通过di / ioc系统进行选择和实例化。

  • 仅在实现部分中声明具体的实现类。

  • 使用类构造函数而不是初始化部分。



Btw,我知道使用类构造函数智能链接的优势在于希望将一个单元包含在足以使课堂可用的情况下相互抵触。我想使用类构造函数而不是初始化部分,其他原因也是如此。而且我想把所有的类初始化/注册代码保存在一起,而不必在类构造函数和初始化部分之间分割。



问题



我想将类的注册工厂放在类构造函数中。不幸的是,编译器不认为通过在其自己的类构造函数中使用它的类型触摸。



当我将注册函数放在初始化部分,那么编译器会认为类被触摸并调用类构造函数。但是,这违反了我在类构造函数中保留所有类初始化代码的对象。



两个问题




  • 编译器应该在自己的类构造函数触摸类中考虑使用类,还是太多希望编译器能够使用?

  • 有没有人有任何聪明的想法,我如何仍然可以实现我的目标,而不使用初始化部分?



示例



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

 code> TSite = class abstract(TObject)
函数GetURL:string;虚拟;抽象;
属性URL:string read GetURL;
结束

TSites = class(TList< TSite>);

TThisApplication =类抽象(TObject)
函数站点:TSites;虚拟;抽象;
结束

TThisApplication

$ b $的具体实现类(在实现部分中声明) b

  TThisApplicationConcrete = class(TThisApplication)
类构造函数ClassCreate;
strict private
FSites:TSites;
功能站点:TSites;覆盖
结束

类构造函数TThisApplicationConcrete.ClassCreate;
begin
RegisterImplementorClass(TThisApplication,TThisApplicationConcrete);
结束

函数TThisApplicationConcrete.Sites:TSites;
var
SiteList:TSites;
begin
如果没有分配(FSites)然后开始
SiteList:= TSites.Create; //更改使用工厂
// RetrieveSites(SiteList);
FSites:= SiteList;
结束

结果:= FSites;
结束

获取TThisApplication实例的功能:

  function ThisApplication:TThisApplication; 
var
ImplementorClass:TClass;
begin
ImplementorClass:= GetImplementorClass(TThisApplication);
如果Assigned(ImplementorClass)然后开始
结果:= ImplementorClass.Create as TThisApplication;
end else begin
结果:= nil;
结束
结束

这是当前编码在一个单独的功能,但它可以移动到工厂。 / p>

完整示例代码



如果有人想尝试,我有完整的我的测试项目的代码可在以下网址获取: http://www.bjsoftware.com/delphistuff/stackoverdlow /classconstructors.zip



邮政内容:




  • 4个项目所有使用相同的源文件,仅在条件定义中有所不同(这也是为什么还包括dproj)

  • 4源文件

  • groupproj及其dsk所有4个项目

  • RunTestApps.cmd运行所有4个项目

  • Results.txt与RunTestApps.cmd的运行输出

  • WriteUp.txt与此问题的文本



请记住,在任何时候你需要t o做一个构建所有项目,因为所有的dcu和exe都将进入源目录,否则你将面临很多错误和/或混乱,因为exe没有做它的名称。

解决方案

这是正如预期的。如Uwe所指出的,自引用类构造函数不足以引发包含。将参考放置在初始化部分中将会做到这一点,因为它不在类本身。试图自我参考一个课程进行包容类似于通过拉扯你自己的吊带来将自己从一个深洞中拉出来。


I am writing a simple dependency injection / inversion of control system based on a TDictionary holding abstract class references with their respective implementor classes.

My goals are:

  • Avoid direct instantiation by type (obviously).
  • Inclusion of a class' unit in the dpr should be enough to have it registered and be available for selection and instantiation through the di/ioc system.
  • Declare concrete implementing classes in implementation section only.
  • Use class constructors instead of initialization sections.

Btw, I am aware that using class constructors to take advantage of smart linking and wanting the inclusion of a unit to be enough to make a class available are defeating each other. I want to use class constructors instead of initialization sections for other reasons as well. And I would like to keep all class initialization/registration code together instead of having to split it between the class constructor and initialization section.

Problem

I want the registration of the class into the factory to be in the class constructor. Unfortunately, the compiler doesn't think the class is "touched" by just using its type in its own class constructor.

When I put the registration function in the initialization section, then the compiler does think the class is touched and calls the class constructor. But that defeats the object of my exercise of keeping all class initialization code in the class constructor.

Two questions

  • Should the compiler consider the use of the class in its own class constructor "touching the class" or is that too much to expect the compiler to do?
  • Does anybody have any clever ideas on how I can still achieve my goals without using the initialization section?

Example

The abstract classes used in the application:

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;

The concrete implementing class (declared in the implementation section!) for 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;

The function to get an instance of 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;

This is currently coded in a separate function, but it w/could be moved to the factory.

Full example code

If anybody would like to experiment, I have the full code of my test projects available at : http://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip

Zip contents:

  • 4 projects all using the same source files, differing only in conditional defines (that's why the dproj's are also included)
  • 4 source files
  • groupproj and its dsk with all 4 projects
  • RunTestApps.cmd to run all 4 projects
  • Results.txt with the output of my run of the RunTestApps.cmd
  • WriteUp.txt with the text of this question

Please bear in mind that at all times you need to do a "Build All Projecs" because all dcu's and exe's are going to the source dir and otherwise you are going to face a lot of errors and/or confusion because the exe isn't doing what its name indicates.

解决方案

This is as expected. As Uwe pointed out, a self-referential class constructor isn't enough to trigger inclusion. Placing the reference in the initialization section will do the trick since that is outside the class itself. Trying to self-reference a class for inclusion is akin to trying pull yourself out of a deep hole by pulling on your own suspenders.

这篇关于当类注册在该类构造函数中完成时,不会调用类构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆