2009-12-08 3 views
4

Недавно я нашел фрагмент кода, который создает экземпляр 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, но его конструктор не используется.

ответ

5

Конструктор TRipple не вызывается, потому что он не является виртуальным.

Когда вы строите объект из ссылки на класс, компилятор не знает, что такое конечный тип класса, поэтому он не может назначить правильный конструктор в коде. Все, что он знает, это то, что он спускается с TPersistent, поэтому он выписывает код для вызова конструктора для TPersistent, который является TObject.Create. Если вы хотите вызвать правильный конструктор, вы должны сделать это практически.

Существует уже виртуальный конструктор, определенный для чтения классов из имени класса. Он определен в TComponent. Извлеките TRipple из TComponent и переопределите его виртуальный конструктор (тот, который принимает владельца как параметр), а затем ваш код будет работать.

+0

Thanx много, Мейсон. Сейчас это работает .... Чудесный ... :-) – lyborko

+0

Рад быть в состоянии помочь! –

5

Возможно, вы не захотите использовать TComponent, и есть другой способ сделать это.

добавить ссылку на свой класс

TTrippleClass = class of TTripple; 

Тогда ваш ButtonClick становится:

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; 
+0

Вы пытались скомпилировать это? Это не сработает из-за двойного объявления TCustomTripple (как «TPersistent» и «class TCustomTripple»). –

+0

Я сделал, но затем скопировал его (вручную), поскольку у меня есть Delphi на другой машине, на тот, на который я отправлял ответ. Я проверю его. – Steve

+0

Спасибо, Кен, ваш первый пример отлично работает. Я ценю. Во втором я не мог усложнить это - точно так же, как вы сказали. Для моего ответа Мейсона достаточно ... – lyborko

Смежные вопросы