简体   繁体   English

Delphi - 从字符串创建类

[英]Delphi - Create class from a string

I got code like this 我有这样的代码

name := 'Foo';
If name = 'Foo' then
  result := TFoo.Create
else if name = 'Bar' then 
  result := TBar.Create
else if name = 'FooFoo' then
  result := TFooFoo.Create;

Is there a way just to do 有办法吗?

result := $name.create

or some way of creating class based of a variable value? 或者某种基于变量值创建类的方法?

All the classes extended the same base class. 所有类都扩展了相同的基类。

Starting with Delphi 2010, the enhanced RTTI allows you do this without having to creating your own Class Registry. 从Delphi 2010开始,增强的RTTI允许您在不必创建自己的类注册表的情况下执行此操作。

Using the RTTI Unit you have several options available. 使用RTTI单元,您可以使用多种选项。

For Parameter Less Constructors one of the easiest is. 对于参数较少的构造函数,最简单的一个是。

var
 C : TRttiContext;
 O : TObject;
begin
  O := (C.FindType('UnitName.TClassName') as TRttiInstanceType).MetaClassType.Create;
  ...
 end;

Here is an example of passing a parameter, using the TRttiMethod.Invoke() 以下是使用TRttiMethod.Invoke()传递参数的示例

var
 C : TRttiContext;
 T : TRttiInstanceType;
 V : TValue;

begin
  T := (C.FindType('StdCtrls.TButton') as TRttiInstanceType);
  V := T.GetMethod('Create').Invoke(T.metaClassType,[self]);
  (V.AsObject as TWinControl).Parent := self;
end;

I wrote several articles on the RTTI unit as there is many options available. 我在RTTI单元上写了几篇文章 ,因为有很多选择。


Updated Based on David Request: 根据David请求更新

Comparing the usage of construction using the Class Type (Virtual Constructor) with the TRttiType.Invoke 使用类类型(虚拟构造函数)与TRttiType.Invoke比较构造的用法

Class Type Method: (Virtual Constructor) 类类型方法:(虚拟构造函数)

  • Works in all version of Delphi 适用于所有版本的Delphi
  • Produces Faster Code 生成更快的代码
  • Requires knowledge of ancestry at compile time. 在编译时需要祖先的知识。
  • Requires a Class Registry to look up a Class by a String Name (Such as mentioned by RRUZ) 需要类注册表以字符串名称查找类(如RRUZ所述)

TRttiType.Invoke() method TRttiType.Invoke()方法

  • Only works in Delphi 2010 or later. 仅适用于Delphi 2010或更高版本。
  • Slower code 代码较慢
  • Implements a Class Registry that takes Name conflicts into account 实现一个将名称冲突考虑在内的类注册表
  • Requires NO knowledge of ancestry at compile time. 需要在编译的时候祖先一无所知

I personally find each serves a different purpose. 我个人认为每个都有不同的用途。 If I know all the types up front the I use the Class Type Method. 如果我知道前面的所有类型,我使用类类型方法。

您可以使用GetClass函数,但必须先使用RegisterClassRegisterClasses方法注册类。

GetClass(const AClassName: string): TPersistentClass;

The normal way to do this is with virtual constructors. 执行此操作的常规方法是使用虚拟构造函数。 A good example is TComponent which you are no doubt familiar. 一个很好的例子是TComponent ,你无疑是熟悉的。

TComponent has the following constructor: TComponent具有以下构造函数:

constructor Create(AOwner: TComponent); virtual;

The other key to this is TComponentClass which is declared as class of TComponent . 另一个关键是TComponentClass ,它被声明为class of TComponent

When the VCL streams .dfm files it reads the name of the class from the .dfm file and, by some process that we don't need to cover here, converts that name into a variable, ComponentClass say of type TComponentClass . 当VCL流.dfm文件时,它从.dfm文件中读取类的名称,并且通过我们不需要在此处覆盖的某个过程,将该名称转换为变量, ComponentClass称为TComponentClass类型。 It can then instantiate the object with: 然后它可以用以下实例化对象:

Component := ComponentClass.Create(Owner);

This is the big advantage of having a virtual constructor and I would encourage you to take the same approach. 这是拥有虚拟构造函数的一大优势,我鼓励您采用相同的方法。

If you have to use a string to identify the class then you'll still need to come up with a lookup routine to convert from the string class name to a class reference. 如果必须使用字符串来标识类,那么您仍然需要提供一个查找例程来将字符串类名转换为类引用。 You could, if convenient, hook into the same VCL mechanism that TComponent uses, namely RegisterClass . 如果方便的话,您可以挂钩到TComponent使用的相同VCL机制,即RegisterClass

Alternatively if you could replace name in your code with a class reference then you could write: 或者,如果您可以使用类引用替换代码中的name ,那么您可以编写:

type
  TFoo = class
    constructor Create; virtual;
  end;
  TBar = class(TFoo);

  TFooClass = class of TFoo;

var
  MyClass: TFooClass;

...

MyClass := TFoo;
result := MyClass.Create;//creates a TFoo;

MyClass := TBar;
result := MyClass.Create;//creates a TBar;

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

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