2010-03-28 89 views
1

是否可以通過調用方法在運行時基於類型創建對象。在運行時根據類類型創建Delphi對象

我所試圖實現的是

var 
    lForm1 : TForm; 
    lForm2 : TForm; 
begin 
    CreateObjects([lForm1, lForm2]); 
    // After this call I have the variables initialized and I can use them. 
end; 
+0

哪個Delphi版本? D2010從上到下徹底改革了RTTI,這可能會改變你如何做到這一點。 – 2010-03-28 22:22:46

+0

我正在使用Delphi 2006. – Sandeep 2010-03-28 22:42:27

回答

7

中有問題的資料不足。

表單對象(在問題中)的「類型」來自哪裏?它只是一個類型名稱? CreateObjects()如何發現每個對象所需的類型?

它不能來自傳入的對象引用的「類型」,因爲這可能(並且幾乎肯定會如您的示例中那樣)只是所需的具體類型最終從中派生的基本類型。

沒有關於您的具體實施目標和約束的更多詳細信息,完整的具體答案是不可能的。

然而,在你尋求可以通過虛擬構造的組合來實現,由VCL提供的的RegisterClass/的findClass基礎設施籠統。

簡單來說,你會,介紹使用實例化類[爲TComponent共同構造得出這個已經存在的的表單類創建(業主:TComponent)基類構造]。

在運行時可以再獲得任何(註冊)使用的findClass('TClassName'類的引用。這將返回一個類引用,使用它可以然後調用適當的虛擬構造:

type 
    TFoo = class .... 
    TFooClass = class of TFoo; 

    // etc 


    var 
    someClass: TFooClass; 
    someObj: TFoo; 
    begin 
    someClass := TFooClass(FindClass('TFooDerivedClass')); 
    someObj := someClass.Create(nil); 
     : 

注意在該TFooDerivedClass以上是最終從TFooClass導出(並且假設爲簡單起見以導出類依次從TComponent開始,並在本例中用NIL所有者實例化)。已經在類型系統中註冊的類可以使用FindClass()找到。這包括您的應用程序中某些DFM引用的任何控件或組件類。任何需要註冊的其他類都可以使用RegisterClass()進行明確註冊。

您的特定應用程序如何識別涉及的對象類型以及類型名稱到其他任意識別系統的映射是您必須注意的實現細節。

+1

您可以調用相應的*非虛擬*構造函數並獲得相同的效果。虛擬構造函數和類引用是相關的,但不是相互依賴的概念。 – 2010-03-29 15:14:10

+0

是的,當然 - 我的錯誤。感謝您的澄清。 – Deltics 2010-03-29 20:23:29

0

報價在亨克的回答您的評論:

這就是我不想做的事。我有很多服務器端方法,我在運行時創建了很多控件,我想知道如上創建對象會減少代碼。

你是什麼意思的「很多」?

如果你的意思是很多類型完全相同的組件(例如:「but1,but2,but3,.. but55:TButton;」),那麼改變你的代碼並使用一個數組來表示你的變量 - 然後你就可以做一個簡單的循環來創建它們。如果你的意思是很多不同類型的組件(例如:but1:TAnimatedButton; but2:TFlatButton; but3:T3DButton;),我看不到任何簡單的方法來做到這一點,我認爲你會創建一個小調試地獄比什麼都重要。

1

未經測試的概念代碼:

function instantiate(var instancevars : array of tobject; 
       const classtypes : array of TBaseClassType):boolean; 

begin 
    if (length(instancevars)=0) or (length(instancevars)<>length(classtypes)) then 
    exit(false); 
    for i:=0 to length(instancevars)-1 do 
    instancevars[i]:=classtypes[i].create; 
    result:=true; 
end; 

然後使用

instantiate([lform1,lform2],[tform1,tform2]); 

,使其工作。

注意這個工作「TBaseClassType」必須是用於該函數的所有類的一些基類,並且有一個虛擬構造函數(例如TPersistent?)。可能您還需要更正.create行(例如,添加(NIL))

您無法從變量獲取類型,該信息僅適用於編譯時。

+0

只有後代類需要在構造函數中做不同的事情時,構造函數才需要虛擬化。使用非虛擬構造函數仍然會創建正確類型的實例,並且所有其他虛擬方法仍然會正確調用,包括'AfterConstruction'。 – 2010-03-29 15:00:24

+0

您可以將TBaseClassType更改爲TObject,它將適用於任何類。 – skamradt 2010-03-29 16:29:31

+0

@skamradt重寫構造函數將不會被調用 – mjn 2010-03-29 18:23:51