Delphi - 从字符串创建类

时间:2011-04-24 19:38:40

标签: delphi oop object

我有这样的代码

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;

有没有办法

result := $name.create

或基于变量值创建类的某种方式?

所有类都扩展了相同的基类。

3 个答案:

答案 0 :(得分:27)

从Delphi 2010开始,增强的RTTI允许您在不必创建自己的类注册表的情况下执行此操作。

使用RTTI单位,您有多种选择。

对于参数较少的构造函数,最简单的一个是。

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

以下是使用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;

我在RTTI单元上写了several articles,因为有很多选项。


已更新基于David请求:

使用类类型(虚拟构造函数)与TRttiType.Invoke

比较构造的用法

类类型方法:(虚拟构造函数)

  • 适用于所有版本的Delphi
  • 制作更快的代码
  • 在编译时需要了解祖先。
  • 需要类注册表以字符串名称查找类(如RRUZ所述)

TRttiType.Invoke()方法

  • 仅适用于Delphi 2010或更高版本。
  • 较慢的代码
  • 实现将名称冲突考虑在内的类注册表
  • 在编译时需要 NO 了解祖先。

我个人觉得每个都有不同的用途。如果我知道前面的所有类型,我使用类类型方法。

答案 1 :(得分:16)

您可以使用GetClass功能,但必须先使用RegisterClassRegisterClasses方法注册课程。

GetClass(const AClassName: string): TPersistentClass;

答案 2 :(得分:10)

执行此操作的常规方法是使用虚拟构造函数。一个很好的例子是TComponent,你无疑是熟悉的。

TComponent具有以下构造函数:

constructor Create(AOwner: TComponent); virtual;

另一个关键是TComponentClass,它被声明为class of TComponent

当VCL流式传输.dfm文件时,它会从.dfm文件中读取该类的名称,并且通过我们不需要在此处覆盖的某个过程,将该名称转换为变量,ComponentClass说类型为TComponentClass。然后它可以使用:

实例化对象
Component := ComponentClass.Create(Owner);

这是拥有虚拟构造函数的一大优势,我鼓励您采用相同的方法。

如果必须使用字符串来标识类,那么您仍然需要提供一个查找例程来将字符串类名转换为类引用。如果方便的话,您可以使用TComponent使用的相同VCL机制,即RegisterClass

或者,如果您可以使用类引用替换代码中的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;