views:

881

answers:

3

I'd like to instantiate a class but I only have its name in a string. Is there a way?

+19  A: 

This is from Delphi help (Delphi 2006, but also available from at least Delphi 7):

Syntax function GetClass(const AClassName: string): TPersistentClass;

Description Call GetClass to obtain a class from a class name. This class can be used as a parameter to routines that require a class. The Class must be registered before GetClass can find it. Form classes and component classes that are referenced in a form declaration (instance variables) are automatically registered when the form is loaded. Other classes can be registered by calling RegisterClass or RegisterClasses .

Here some sample code. Works as such only because TButton is a TControl and therefore the typecast is valid.

procedure TForm1.FormCreate(Sender: TObject);
begin
  RegisterClasses([TButton, TForm]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  CRef : TPersistentClass;
  AControl : TControl;
begin
  CRef := GetClass('TButton');
  if CRef<>nil then
  begin
     AControl := TControl(TControlClass(CRef).Create(Self));
     with AControl do
     begin
        Parent := Self;
        Width := 50;
        Height := 30;
     end;
  end;
end;
Ralph Rickenbach
Great solution. But now I've ran into another issue. The class I'd like to instantiate is a class of my own that implements an Interface.And registerClass must be called with a persistent class. Any idea?
Ricardo Acras
Is it possible to derive your class or one of it's ancestors from TPersistent?
Ralph Rickenbach
I don't believe so, since it implements a interface and it has to derive from TInterfaceObject
Ricardo Acras
I fount TInterfacedPersistent, just perfect. Thanks.
Ricardo Acras
Never mind my previous suggestion. TInterfacedPersistent is what you want. I thought it existed but couldn't remember the name.
Jim McKeeth
You don't have to use the VCL's RegisterClass mechanism if you don't want to change your class hierarchy - write your own. Just have a look at TRegGroup.GetClass, TRegGroup.RegisterClass etc in Classes.pas. You can simplify the code by throwing out the RegGroups layer.
Ulrich Gerhardt
A: 

When I needed to do that, I Built my own Object Factory that uses a specially subclassed TStringList, I'm currently using Delphi 7 so the string list class supports only attach a Object to a String, then I got to subclass TStringList to make it possible handle Class Types too, so now I can instantiate a object just passing it's class name to the factory. Works that way:

1st - Load a Singleton Object Factory;
2st - Register any object to the factory, could be in the initialization section of the unit;

The main Factory's methods could be: isClassRegistered, registerClass, instantiateClass(ClassName: STring): TObject;

This way I can instantiate any object, or use a previous instantiated object, or even, a subset of they.

I rather use a Enumerated type instead of a string to identify a Class.

Remarks: It's a very, very terse example, a completely functional code is more complex, but, belive me, not too much.

Gedean Dias
A: 

Hi,

please may you tell me please, what's wrong with this code? I reused the code above:

. . .

TTripple=class (TPersistent)
private
     FFont:TFont;
public
     constructor Create;
     Destructor Destroy;override;
published
     property Font:TFont read FFont write  FFont;
end;

var  Form1: TForm1;
    implementation

{$R *.dfm}

constructor TTripple.Create;
          begin
          inherited;
          FFont:=TFont.Create;
          end;

destructor TTripple.Destroy;
  begin
  FFont.Free;
  inherited;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterClasses([TButton, TForm, TTripple]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  CRef : TPersistentClass;
  APer : TPersistent;
begin
  CRef := GetClass('TTripple');
  if CRef<>nil then
  begin
     APer := TPersistent(TPersistentClass(CRef).Create);
     ShowMessage(APer.ClassName);  //  TTriple  (correct)
     if APer is TTripple then (APer as TTripple).Font.Color:=90;

     /// Here  I get error message, because TTriple was not created yet... ?!?!?!

  end;
end;
lyborko
This is not how StackOverflow works. If you have a question that relates to an earlier one, please ask a new question while providing a link to the one you are referring to.
mghie