简体   繁体   English

根据类类型在运行时创建Delphi对象

[英]Creating Delphi Objects at runtime based on class type

Is it possible to create objects at runtime based on it's type by calling a method. 是否可以通过调用方法根据类型在运行时创建对象。

What I am trying to achieve is 我想要实现的是

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

There is insufficient information in the question. 问题中没有足够的信息。

Where does the "type" of the form objects (in the question) come from? 表单对象(在问题中)的“类型”从何而来? Is it simply a type name? 它只是类型名称吗? How does CreateObjects() discover the type that is required for each object? CreateObjects()如何发现每个对象所需的类型?

It cannot come from the "type" of the object reference passed in, as this may be (and almost certainly will be, as in your example) merely a base type from which the required concrete type will ultimately derive. 它不能来自传入的对象引用的“类型”,因为它可能是(并且几乎肯定会是您的示例中所定义的)仅仅是基本类型,所需的具体类型最终将从该基本类型派生。

Without more detailed information about your specific implementation goals and constraints, a complete, concrete answer is not possible. 没有有关您的特定实施目标和约束的更详细的信息,就不可能获得完整而具体的答案。

However, in general terms what you seek may be achieved by a combination of virtual constructors and the RegisterClass / FindClass infrastructure provided by the VCL. 但是,总的来说,您可以通过将虚拟构造函数和VCL提供的RegisterClass / FindClass基础结构相结合来实现。

In simple terms, you would have a base class that introduces the common constructor used to instantiate your classes [for TComponent derived classes this already exists in the form of the Create( Owner: TComponent ) constructor]. 简而言之,您将拥有一个基类,该基类引入了用于实例化您的类的公共构造函数[对于TComponent派生类,它已经以Create( Owner:TComponent构造函数的形式存在]。

At runtime you can then obtain a reference to any (registered) class using FindClass( 'TClassName' ) . 然后,在运行时,您可以使用FindClass( 'TClassName'获得对任何(注册)类的引用。 This will return a class reference with which you can then invoke the appropriate virtual constructor: 这将返回一个类引用,您可以通过该类引用调用适当的虚拟构造函数:

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

    // etc


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

Note in the above that TFooDerivedClass is a class that ultimately derives from TFooClass (and is assumed for simplicity to derive in turn from TComponent and is instantiated with a NIL owner in this case). 注意在上面的那TFooDerivedClass是最终从TFooClass导出(并且假设为简单起见,以依次从TComponent派生和实例化与在这种情况下一个NIL所有者)的类。 Classes that are already registered with the type system can be found using FindClass() . 可以使用FindClass()找到已经在类型系统中注册的类。 This includes any control or component class that is referenced by some DFM in your application. 这包括应用程序中某些DFM引用的任何控件或组件类。 Any additional classes that need to be registered may be explicitly registered using RegisterClass() . 可以使用RegisterClass()显式注册需要注册的任何其他类。

How your specific application identifies the types of objects involved and any mapping of type names onto other arbitrary system of identification is an implementation detail that you must take care of. 您的特定应用程序如何标识所涉及的对象的类型以及类型名称到其他任意标识系统的映射是您必须注意的实现细节。

Untested concept code: 未经测试的概念代码:

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;

Then use 然后使用

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

to make it work. 使它工作。

Note for this to work "TBaseClassType" must be some baseclass for all classes used for this function, and have a virtual constructor (eg TPersistent?). 为此,请注意,“ TBaseClassType”必须是用于此函数的所有类的某个基类,并且必须具有虚拟构造函数(例如TPersistent?)。 Possibly you also need to correct the .create line (eg add (NIL) ) 可能还需要更正.create行(例如add(NIL))

You can't get a type from a variable, the information is only available compiletime. 您无法从变量获取类型,该信息仅在编译时可用。

Quoting your comment on Henk's answer : 引用您对Henk的回答的评论:

That's what I don't want to do. 那就是我不想做的。 I have a lot of server side methods where I create a lot of controls at runtime and I was wondering is creating objects as above would reduce the code. 我有很多服务器端方法,我在运行时创建了很多控件,我想知道像上面那样创建对象会减少代码。

What do you mean by "a lot"? “很多”是什么意思?

If you mean a lot of components of exactly the same type (eg : "but1, but2, but3, .. but55 : TButton;" ) then change your code and use an array to represent your variables - you can then make a simple loop to create them. 如果您要表示很多完全相同类型的组件(例如:“ but1,but2,but3,.. but55:TButton;”),请更改代码并使用数组来表示变量-然后可以进行简单循环创建它们。

If you mean a lot of components of different types (eg : but1 : TAnimatedButton; but2 : TFlatButton; but3 : T3DButton;), I don't see any simple method to do this, and I think you would create a small debugging hell more than anything else. 如果您指的是许多不同类型的组件(例如:but1:TAnimatedButton; but2:TFlatButton; but3:T3DButton;),我看不到任何简单的方法可以做到这一点,我想您会创建一个小的调试地狱比什么都重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM