基于类类型在运行时创建Delphi对象

基于类类型在运行时创建Delphi对象,delphi,runtime,Delphi,Runtime,是否可以通过调用方法在运行时基于对象的类型创建对象 我想要达到的是 var lForm1 : TForm; lForm2 : TForm; begin CreateObjects([lForm1, lForm2]); // After this call I have the variables initialized and I can use them. end; 这个问题没有足够的资料 问题中表单对象的类型来自哪里?它只是一个类型名吗?CreateObjects如何发现每

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

我想要达到的是

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

这个问题没有足够的资料

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

它不能来自传入的对象引用的类型,因为这可能是并且几乎肯定会是,在您的示例中,它仅仅是一个基本类型,所需的具体类型最终将从中派生

如果没有关于具体实现目标和约束的更详细信息,就不可能有完整、具体的答案

但是,一般来说,您所寻求的可以通过虚拟构造函数和VCL提供的RegisterClass/FindClass基础结构的组合来实现

简单地说,您将拥有一个基类,该基类引入了用于实例化类的公共构造函数[对于TComponent派生类,它已经以CreateOwner: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派生的类,为了简单起见,假定它依次从TcoComponent派生,并且在本例中使用NIL所有者实例化。可以使用FindClass找到已在类型系统中注册的类。这包括应用程序中某些DFM引用的任何控件或组件类。任何需要注册的附加类都可以使用RegisterClass显式注册


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

问题中没有足够的信息

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

它不能来自传入的对象引用的类型,因为这可能是并且几乎肯定会是,在您的示例中,它仅仅是一个基本类型,所需的具体类型最终将从中派生

如果没有关于具体实现目标和约束的更详细信息,就不可能有完整、具体的答案

但是,一般来说,您所寻求的可以通过虚拟构造函数和VCL提供的RegisterClass/FindClass基础结构的组合来实现

简单地说,您将拥有一个基类,该基类引入了用于实例化类的公共构造函数[对于TComponent派生类,它已经以CreateOwner: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派生的类,为了简单起见,假定它依次从TcoComponent派生,并且在本例中使用NIL所有者实例化。可以使用FindClass找到已在类型系统中注册的类。这包括应用程序中某些DFM引用的任何控件或组件类。任何需要注册的附加类都可以使用RegisterClass显式注册


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

引用您对Henk答案的评论:

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

你说的很多是什么意思

如果您指的是许多完全相同类型的组件,例如:but1、but2、but3。。but55:t按钮;然后更改代码并使用数组来表示变量-然后可以创建一个简单的循环来创建它们


如果您指的是许多不同类型的组件,例如:but1:TAnimatedButton;but2:TFlatButton;但是3:T3D按钮;,我看不到任何简单的方法可以做到这一点,我认为你会创造一个小的调试地狱比其他任何东西都重要。

引用你对Henk答案的评论:

这就是我不想做的。我有很多服务器端方法,我在运行时创建了很多控件,我想知道如上所述创建对象是否会减少代码< /p> 你说的很多是什么意思

如果您指的是许多完全相同类型的组件,例如:but1、but2、but3。。but55:t按钮;然后更改代码并使用数组来表示变量-然后可以创建一个简单的循环来创建它们

如果您指的是许多不同类型的组件,例如:but1:TAnimatedButton;but2:TFlatButton;但是3:T3D按钮;,我看不到任何简单的方法可以做到这一点,我认为你会创建一个小型的调试地狱比其他任何东西都重要。

未经测试的概念代码:

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;
让它工作

注意:要使其正常工作,TBaseClassType必须是用于此函数的所有类的某个基类,并且具有虚拟构造函数,例如TPersistent?。可能您还需要更正.create行,例如add NIL

无法从变量获取类型,信息仅在编译时可用。

未测试的概念代码:

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;
让它工作

注意:要使其正常工作,TBaseClassType必须是用于此函数的所有类的某个基类,并且具有虚拟构造函数,例如TPersistent?。可能您还需要更正.create行,例如add NIL


您无法从变量中获取类型,信息仅在编译时可用。

哪个Delphi版本?D2010从上到下彻底检修了RTTI,这可能会改变您的操作方式。哪个Delphi版本?D2010从上到下彻底检修了RTTI,这可能会改变您的操作方式。仅当子类需要在构造函数中执行不同的操作时,构造函数才需要是虚拟的。使用非虚拟构造函数仍将创建正确类型的实例,所有其他虚拟方法仍将正确调用,包括AfterConstruction。您可以将TBaseClassType更改为ToObject,它将适用于任何类。@skamradt重写的构造函数将不会被调用,我只是不想让它看起来过于宽泛,因为它有一些限制。只有当子类需要在构造函数中执行不同的操作时,构造函数才需要是虚拟的。使用非虚拟构造函数仍将创建正确类型的实例,所有其他虚拟方法仍将正确调用,包括AfterConstruction。您可以将TBaseClassType更改为ToObject,它将适用于任何类。@skamradt重写的构造函数将不会被调用,我只是不想让它看起来过于宽泛,因为它有一些限制。您可以调用适当的非虚拟构造函数并获得相同的效果。虚拟构造函数和类引用是相关的,但不是相互依赖的概念。仅注册TFoo将找不到TFooDerivedClass。我必须同时注册每个TFooDerivedClass吗?@kobik是的。FindClass只能查找已使用RegisterClass注册的类。注册一个基类并不会自动注册所有的子类——基类甚至不知道可能存在哪些子类!您可以调用适当的非虚拟构造函数并获得相同的效果。虚拟构造函数和类引用是相关的,但不是相互依赖的概念。仅注册TFoo将找不到TFooDerivedClass。我必须同时注册每个TFooDerivedClass吗?@kobik是的。FindClass只能查找已使用RegisterClass注册的类。注册一个基类并不会自动注册所有的子类——基类甚至不知道可能存在哪些子类!