2010-03-28 118 views
1

是否可以通过调用方法在运行时基于类型创建对象。在运行时根据类类型创建Delphi对象

我所试图实现的是

var 
    lForm1 : TForm; 
    lForm2 : TForm; 
begin 
    CreateObjects([lForm1, lForm2]); 
    // After this call I have the variables initialized and I can use them. 
end; 
+0

哪个Delphi版本? D2010从上到下彻底改革了RTTI,这可能会改变你如何做到这一点。 – 2010-03-28 22:22:46

+0

我正在使用Delphi 2006. – Sandeep 2010-03-28 22:42:27

回答

7

中有问题的资料不足。

表单对象(在问题中)的“类型”来自哪里?它只是一个类型名称? CreateObjects()如何发现每个对象所需的类型?

它不能来自传入的对象引用的“类型”,因为这可能(并且几乎肯定会如您的示例中那样)只是所需的具体类型最终从中派生的基本类型。

没有关于您的具体实施目标和约束的更多详细信息,完整的具体答案是不可能的。

然而,在你寻求可以通过虚拟构造的组合来实现,由VCL提供的的RegisterClass/的findClass基础设施笼统。

简单来说,你会,介绍使用实例化类[为TComponent共同构造得出这个已经存在的的表单类创建(业主:TComponent)基类构造]。

在运行时可以再获得任何(注册)使用的findClass('TClassName'类的引用。这将返回一个类引用,使用它可以然后调用适当的虚拟构造:

type 
    TFoo = class .... 
    TFooClass = class of TFoo; 

    // etc 


    var 
    someClass: TFooClass; 
    someObj: TFoo; 
    begin 
    someClass := TFooClass(FindClass('TFooDerivedClass')); 
    someObj := someClass.Create(nil); 
     : 

注意在该TFooDerivedClass以上是最终从TFooClass导出(并且假设为简单起见以导出类依次从TComponent开始,并在本例中用NIL所有者实例化)。已经在类型系统中注册的类可以使用FindClass()找到。这包括您的应用程序中某些DFM引用的任何控件或组件类。任何需要注册的其他类都可以使用RegisterClass()进行明确注册。

您的特定应用程序如何识别涉及的对象类型以及类型名称到其他任意识别系统的映射是您必须注意的实现细节。

+1

您可以调用相应的*非虚拟*构造函数并获得相同的效果。虚拟构造函数和类引用是相关的,但不是相互依赖的概念。 – 2010-03-29 15:14:10

+0

是的,当然 - 我的错误。感谢您的澄清。 – Deltics 2010-03-29 20:23:29

0

报价在亨克的回答您的评论:

这就是我不想做的事。我有很多服务器端方法,我在运行时创建了很多控件,我想知道如上创建对象会减少代码。

你是什么意思的“很多”?

如果你的意思是很多类型完全相同的组件(例如:“but1,but2,but3,.. but55:TButton;”),那么改变你的代码并使用一个数组来表示你的变量 - 然后你就可以做一个简单的循环来创建它们。如果你的意思是很多不同类型的组件(例如:but1:TAnimatedButton; but2:TFlatButton; but3:T3DButton;),我看不到任何简单的方法来做到这一点,我认为你会创建一个小调试地狱比什么都重要。

1

未经测试的概念代码:

function instantiate(var instancevars : array of tobject; 
       const classtypes : array of TBaseClassType):boolean; 

begin 
    if (length(instancevars)=0) or (length(instancevars)<>length(classtypes)) then 
    exit(false); 
    for i:=0 to length(instancevars)-1 do 
    instancevars[i]:=classtypes[i].create; 
    result:=true; 
end; 

然后使用

instantiate([lform1,lform2],[tform1,tform2]); 

,使其工作。

注意这个工作“TBaseClassType”必须是用于该函数的所有类的一些基类,并且有一个虚拟构造函数(例如TPersistent?)。可能您还需要更正.create行(例如,添加(NIL))

您无法从变量获取类型,该信息仅适用于编译时。

+0

只有后代类需要在构造函数中做不同的事情时,构造函数才需要虚拟化。使用非虚拟构造函数仍然会创建正确类型的实例,并且所有其他虚拟方法仍然会正确调用,包括'AfterConstruction'。 – 2010-03-29 15:00:24

+0

您可以将TBaseClassType更改为TObject,它将适用于任何类。 – skamradt 2010-03-29 16:29:31

+0

@skamradt重写构造函数将不会被调用 – mjn 2010-03-29 18:23:51