如何从提供类名的字符串创建实例?

时间:2009-12-08 10:50:04

标签: delphi

最近我发现了一段代码,它从一个字符串中创建了一个TButton实例:'TButton'被用作参数。

请参阅"Is there a way to instantiate a class by its name in Delphi?"

我正在尝试将任何对象的已发布属性保存到XML文件(工作正常),最近我想从XML文件中重新创建这些对象。在这个文件中写入了应该创建哪个类(例如TButton),然后是一个属性列表,这些属性应该加载到这个运行时创建的对象中。

上面的示例显示了如何执行此操作,但它不适用于我自己的类。请参阅以下代码:

  TTripple=class (TPersistent)
    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('TButton');
  CRef := GetClass('TTripple');
  if CRef<>nil then
  begin
     APer := TPersistent(TPersistentClass(CRef).Create);
     ShowMessage(APer.ClassName);  // shows TTripple, what is correct
     if APer is TTripple then (APer as TTripple).Font.Color:=90;

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

  end;
end;

我无法通过。可能已创建了TTripple对象,但未使用其构造函数。

2 个答案:

答案 0 :(得分:5)

没有调用TRipple构造函数,因为它不是虚拟的。

当您从类引用构造对象时,编译器不知道最终的类类型是什么,因此它无法在代码中分配正确的构造函数。它只知道它是从TPersistent下降的,所以它写出代码来调用TPersistent的构造函数,即TObject.Create。如果你想调用正确的构造函数,你必须虚拟地进行。

已经定义了一个虚拟构造函数,用于从类名中读取类。它在TComponent中定义。使TRipple从TComponent下降并覆盖其虚拟构造函数(将所有者作为参数的构造函数),然后您的代码将起作用。

答案 1 :(得分:5)

您可能不想使用TComponent,还有另一种方法。

添加对您的课程的引用

TTrippleClass = class of TTripple;

然后你的按钮点击:

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

现在您可能希望拥有多个Tripple类型,然后创建自定义祖先。

TCustomTripple = class(TPersistent)
public
  constructor Create;virtual;
end;

TCustomTrippleClass = class of TCustomTripple;

TTripple = class(TCustomTripple)
strict private
  fFont : TFont;
public
  constructor Create;override;
  destructor Destroy;override;
  property Font : TFont read fFont;
end;


constructor TCustomTripple.Create;
begin
  inherited Create;
end;

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

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

procedure TForm1.Button1Click(Sender: TObject);
var
  CRef : TCustomTrippleClass;
  APer : TCustomTripple;
begin
  CRef := TCustomTrippleClass(GetClass('TTripple'));
  if CRef<>nil then
  begin
    APer := TCustomTripple(TCustomTrippleClass(CRef).Create);
    ShowMessage(APer.ClassName);  // shows TTripple, what is correct
    if APer is TTripple then (APer as TTripple).Font.Color:=90;
  end;
end;