是否可以在Delphi中将类型存储在变量中?

nic*_*ick 1 delphi

我有三个类,例如(TMyClass1,TMyClass2和TMyClass3)。

我有一个函数,将带有类型名称的字符串作为参数,然后实例化给定类型的类。现在,我正在使用if语句,例如:

if(AFormName = 'xxx1') then
begin
    MyClass := MyClass1.Create;
end else if(AFormName = 'xxx2') then        
begin
    MyClass := MyClass2.Create;
end;
Run Code Online (Sandbox Code Playgroud)

等等..

有没有一种方法可以将类型存储在变量中,以便更改将字符串链接到类型并避免使用它?

如果有帮助,MyClass1,MyClass2和MyClass3都将从另一个类继承...

Rem*_*eau 8

看一下RTL RegisterClass()FindClass()/ GetClass()函数,它们正是针对这种情况而设计的,例如:

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.
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行以下操作:

var
  MyObj: MyBase;
begin
  MyObj := MakeMyClass('MyClass1');
  ...
  MyObj.Free;
end;
Run Code Online (Sandbox Code Playgroud)

缺点是这些类必须从派生TPersistent。如果您不想使用TPersistent,或者您只想使用不同的名称来创建类对象,则设置自定义工厂并不难,例如,使用TDictionary,例如:

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, TMyBaseCreateFunc>.Create;
  MyFactory.Add('xxx1', MyClass1);
  MyFactory.Add('xxx2', MyClass2);
  MyFactory.Add('xxx3', MyClass3);
finalization
  MyFactory.Free;
end.
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行以下操作:

var
  MyObj: MyBase;
begin
  MyObj := MakeMyClass('xxx1');
  ...
  MyObj.Free;
end;
Run Code Online (Sandbox Code Playgroud)