nick
nick

Reputation: 3259

Is it possible to store a type in a variable in Delphi?

I have three classes, for example (TMyClass1, TMyClass2, and TMyClass3).

I have a function that takes as a parameter a string with the name of the type, and then instanciates that class given the type. Right now I'm using if statements, for example:

if(AFormName = 'xxx1') then
begin
    MyClass := MyClass1.Create;
end else if(AFormName = 'xxx2') then        
begin
    MyClass := MyClass2.Create;
end;

Etc..

Is there a way that I can store the type in a variable so I change link the strings to the types and avoid using that?

If it's any help, MyClass1, MyClass2 and MyClass3 all inherit from another class...

Upvotes: 3

Views: 823

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598299

Look at the RTL's RegisterClass() and FindClass()/GetClass() functions, they were designed for exactly this kind of scenario, eg:

interface

uses
  ..., Classes;

type
  MyBase = class(TPersistent)
  public
    constructor Create; virtual;
  end;

  MyBaseClass = class of MyBase;

  MyClass1 = class(MyBase)
  public
    constructor Create; override;
  end;

  MyClass2 = class(MyBase)
  public
    constructor Create; override;
  end;

  MyClass3 = class(MyBase)
  public
    constructor Create; override;
  end;

...

function MakeMyClass(const Name: string): MyBase;

implementation

function MakeMyClass(const Name: string): MyBase;
begin
  Result := MyBaseClass(GetClass(Name)).Create;
end;

...

initialization
  RegisterClasses([MyClass1, MyClass2, MyClass3{, ...}]);

end.

Then you can do this:

var
  MyObj: MyBase;
begin
  MyObj := MakeMyClass('MyClass1');
  ...
  MyObj.Free;
end;

The drawback is that the classes must be derived from TPersistent. If you don't want to use TPersistent, or if you just want to use different names to create your class objects, it is not very hard to setup a custom factory, for instance by using a TDictionary, eg:

interface

type
  MyBase = class
  public
    constructor Create; virtual;
  end;

  MyBaseClass = class of MyBase;

  MyClass1 = class(MyBase)
  public
    constructor Create; override;
  end;

  MyClass2 = class(MyBase)
  public
    constructor Create; override;
  end;

  MyClass3 = class(MyBase)
  public
    constructor Create; override;
  end;

...

function MakeMyClass(const Name: string): MyBase;

implementation

uses
  System.Generics.Collections, System.SysUtils;

var
  MyFactory: TDictionary<string, MyBaseClass>;

function MakeMyClass(const Name: string): MyBase;
begin
  Result := MyFactory[Name].Create;
end;

...

initialization
  MyFactory := TDictionary<string, MyBaseClass>.Create;
  MyFactory.Add('xxx1', MyClass1);
  MyFactory.Add('xxx2', MyClass2);
  MyFactory.Add('xxx3', MyClass3);
finalization
  MyFactory.Free;
end.

Then you can do this:

var
  MyObj: MyBase;
begin
  MyObj := MakeMyClass('xxx1');
  ...
  MyObj.Free;
end;

Upvotes: 12

Related Questions