Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi - Create class from a string

Tags:

object

oop

delphi

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.

like image 297
Wizzard Avatar asked Apr 24 '11 19:04

Wizzard


2 Answers

Starting with Delphi 2010, the enhanced RTTI allows you do this without having to creating your own Class Registry.

Using the RTTI Unit you have several options available.

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()

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.


Updated Based on David Request:

Comparing the usage of construction using the Class Type (Virtual Constructor) with the TRttiType.Invoke

Class Type Method: (Virtual Constructor)

  • Works in all version of 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)

TRttiType.Invoke() method

  • Only works in Delphi 2010 or later.
  • 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.

like image 75
Robert Love Avatar answered Sep 23 '22 13:09

Robert Love


You can use the GetClass function, but before you must register the classes using the RegisterClass or RegisterClasses methods.

GetClass(const AClassName: string): TPersistentClass;
like image 42
RRUZ Avatar answered Sep 26 '22 13:09

RRUZ