Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Create Object from String

1,226 views
Skip to first unread message

Sam

unread,
Oct 24, 2003, 12:01:51 PM10/24/03
to
Hi,

How can I create an object given its classname as a string. for eg: TMyClass
= class(TObject). I want to create a TMyClass instance given 'TMyClass' as a
string variable.

Thanks
SAM


Ian Kirk

unread,
Oct 24, 2003, 12:21:04 PM10/24/03
to
"Sam" <$@M> wrote in message news:3f99...@newsgroups.borland.com...

Try a Google Groups search on "Delphi create object from a string".

HTH,
Ian


David Knaack

unread,
Oct 24, 2003, 12:19:23 PM10/24/03
to

I wrote this a while back, it should give you a start on what you want
to do. Hope it helps.

DK

To create a component knowing only its name:

It must be registered:

RegisterClass( TButton );

or

RegisterClass( AClass.ClassType );

Form types can be registered in their units initialization
section. As long as the unit is used the form will be
registered.


To create the class first get a class refrence to it using
the FindClass or GetClass function:

var MetaClass : TPersistentClass;
MetaClass := FindClass( 'TForm2');

Before creating an instance, cast the MetaClass to the
general type that it is, otherwise you will not be able
to call the correct constructor (so you won't be able
to specify any required parameters).

var ComponentMetaClass : TComponentClass;
ComponentMetaClass := TComponentClass( MetaClass );

Now the constructor can be called:

var AForm: TComponent;
AForm := ComponentMetaClass.Create( self );

AForm now contains a valid instance of the class
specified in the call to FindClass(). Methods of the
component can be called. By typecasting the instance
to the correct class or a valid base class (if you know
it), you can call methods of the object.:

TForm(AForm).Show;

or

var SomeForm : TForm;
SomeForm := TForm( AForm );
SomeForm.Show;


The entire process in a button click:

procedure TForm1.Button1Click(Sender: TObject);
var MetaClass : TPersistentClass;
ComponentMetaClass : TComponentClass;
AForm: TComponent;
begin
MetaClass := FindClass( 'TForm2');
ComponentMetaClass := TComponentClass( MetaClass );
AForm := ComponentMetaClass.Create( self );
TForm(AForm).Show;
end;

This entire procedure can be handled with one line of code:

TForm( TComponentClass( FindClass( 'TForm2' ) ).Create( Self )).Show;

(Ok, three lines, if you count the initialization and Register lines.)

Sam

unread,
Oct 24, 2003, 12:42:27 PM10/24/03
to
Thanks, That works.

However, is there a way this can be implemented for objects not descended
from TPersistent?

Sam


"David Knaack" <david...@cox.net> wrote in message
news:3f99...@newsgroups.borland.com...

David Knaack

unread,
Oct 24, 2003, 12:48:09 PM10/24/03
to
Sam wrote:

> Thanks, That works.
>
> However, is there a way this can be implemented for objects not descended
> from TPersistent?

IIRC, yes, just turn on RTTI for the class you need to work with {$M+}.
I think supporting IInvokable also will cause RTTI to be included.

DK

Marc Rohloff

unread,
Oct 24, 2003, 1:23:24 PM10/24/03
to
On Fri, 24 Oct 2003 12:42:27 -0400, Sam<$@M> said ...

> Thanks, That works.
>
> However, is there a way this can be implemented for objects not descended
> from TPersistent?
Yes.

Firstly everything must descend from a common base class that has a
virtual constructor.

type
TBase=class
public
constructor Create; virtual;
end;
TBaseClass = class of TBase;

type
TMyClass = class(TBase)
...
end;

To Register:
RegisterClass(TPersistent(TMyClass));

To Create:
var c:TBaseClass; o:TBase;
c := TBaseClass(FindClass('TMyClass'));
o := c.create;

Of course this is abusing the registerclass/findclass system a bit. I
towuldn't be too hard to make your own implementation which would be
safer and wouldn't require the typecasting.

implementation

var
ClassList : TStringList;

procedure RegisterMyClass(cl:TBaseClass);
begin
if not assigned(ClassList) then
begin
ClassList := TStringList.create;
ClassList.CaseInsensitive := true;
ClassList.sorted := true;
ClassList.Duplicates := dupError;
end;

ClassList.addobject(cl.classname, TObject(cl) );
end;

function FindMyClass(const name:string):TBaseClass;
var i:integer;
begin
if assigned(ClassList)
then i := ClassList.indexof(name)
else i := -1;
if i<0
then raise exception.createfmt('Class ''%s'' not found', [name] );

result := TBaseClass(ClassList.objects[i]);
end;

finalization
ClassList.Free;
end.

And then:

To Register:
RegisterMyClass(TMyClass);

To Create:
var o:TBase;
o := FindClass('TMyClass').Create;


Marc

Rob Kennedy

unread,
Oct 24, 2003, 1:31:34 PM10/24/03
to
David Knaack wrote:

> Sam wrote:
>> However, is there a way this can be implemented for objects not
>> descended from TPersistent?
>
> IIRC, yes, just turn on RTTI for the class you need to work with
> {$M+}.

Nope. RegisterClass and FindClass work with types fitting the
TPersistentClass mold. If you don't want to descend from TPersistent,
then you need to make up your own class registry. (Run-time type
information is not relevant.) As long as you have control over the class
hierarchy, though, I see little practical reason not to descend from
TPersistent.

--
Rob

Joanna Carter

unread,
Oct 24, 2003, 1:17:59 PM10/24/03
to
Sam wrote:

| However, is there a way this can be implemented for objects not
| descended from TPersistent?

Yes, just create your own list of classes and add whatever classes you want
to it.

TClassRegister = class
class procedure RegisterClass(AClass: TClass);
class function GetClass(const AClassName: string): TClass;
end;

implementation

uses
Contnrs;

var
ClassList: TObjectList = nil;

class procedure TClassRegister.RegisterClass(AClass: TClass);
begin
if ClassList = nil then
ClassList := TObjectList.Create;
ClassList.Add(TObject(AClass));
end;

class function TClassRegister.GetClass(const AClassName: string): TClass;
var
i: Integer;
begin
Result := nil;
if ClassList <> nil then
begin
for i := 0 to Pred(ClassList.Count) do
if TClass(ClassList[i]).ClassName = AClassName then
begin
Result := TClass(ClassList[i]);
Exit;
end;
end;
if Result = nil then
raise Exception.CreateFmt('Cannot find class %s', [AClassName]);
end;

initialization
finalization
ClassList.Free;

end.

I'll send my invoice later :-)

Joanna

--
Joanna Carter
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


Joanna Carter

unread,
Oct 24, 2003, 1:22:34 PM10/24/03
to
Joanna Carter wrote:

Sorry, forgot to say, it is called like this

begin
TClassRegister.RegisterClass(TCustomer);
...
end;

var
aClass: TClass;
begin
aClass := TClassRegister.GetClass('TCustomer');
...
end;

Craig Stuntz [TeamB]

unread,
Oct 24, 2003, 2:03:25 PM10/24/03
to
Rob Kennedy wrote:

> If you don't want to descend from TPersistent,
> then you need to make up your own class registry. (Run-time type
> information is not relevant.)

...but having a virtual constructor is a must, which is probably why
RegisterClass requires TPersistent. You can, of course, create your
own parent class and make its constructor virtual.

-Craig

--
Craig Stuntz [TeamB] . Vertex Systems Corp. . Columbus, OH
Delphi/InterBase Weblog : http://delphi.weblogs.com
InterBase Performance Monitor -- Analyze and control your IB7
server: http://delphi.weblogs.com/IBPerformanceMonitor

Rob Kennedy

unread,
Oct 24, 2003, 3:38:55 PM10/24/03
to
Craig Stuntz [TeamB] wrote:
> ...but having a virtual constructor is a must, which is probably why
> RegisterClass requires TPersistent.

Does TPersistent have a virtual constructor nowadays? In Delphi 5, it
defined no constructor at all. I really see no reason for RegisterClass
to require TPersistent rather than TObject.

--
Rob

Craig Stuntz [TeamB]

unread,
Oct 24, 2003, 3:52:05 PM10/24/03
to
Rob Kennedy wrote:

> Does TPersistent have a virtual constructor nowadays? In Delphi 5, it
> defined no constructor at all. I really see no reason for
> RegisterClass to require TPersistent rather than TObject.

Oops. You're right. No constructor at all.

But it is, nonetheless, important to have a virtual constructor if
you're going to instantiate using FindClass.

And I agree that I can't think of a reason for RegisterClass/FindClass
to require TPersistent, but writing your own class registry is such a
trivial exercise it's hardly worth worrying about.

-Craig

--
Craig Stuntz [TeamB] . Vertex Systems Corp. . Columbus, OH
Delphi/InterBase Weblog : http://delphi.weblogs.com

Please read and follow Borland's rules for the user of their
news server: http://info.borland.com/newsgroups/guide.html

Marc Rohloff

unread,
Oct 29, 2003, 8:11:02 AM10/29/03
to
> var
> ClassList: TObjectList = nil;

Joanna,

Don't forget that TObjectList will try and free it's contents when it is
freed. Since you are storing classes in th elist this will not work.

You are aware that Delphi has had a TClassList type for quite a while?

Marc

Joanna Carter

unread,
Oct 29, 2003, 8:13:38 AM10/29/03
to
Marc Rohloff wrote:

|| var
|| ClassList: TObjectList = nil;

| Don't forget that TObjectList will try and free it's contents when it


| is freed. Since you are storing classes in th elist this will not
| work.

Then call the constructor with the optional False parameter.

| You are aware that Delphi has had a TClassList type for quite a while?

Dooohh!! Yes, now that you remind me :-)

0 new messages