2014-05-10 39 views
0

我得到像'TGroupBox'或'TEdit'數據庫中的字符串...現在我需要檢查元素對他們...我怎麼枚舉字符串鍵入?德爾福 - 如何枚舉字符串來鍵入

我的意思是這樣的:

mystr := 'TGroupBox'; 
If (page.Controls[0] is mystr) then ... 

當然它不會工作,因爲出現錯誤:

E2015操作並不適用於這一運算對象類型

如何我做得對嗎?

+0

你究竟在做什麼? –

+0

我實際上試圖做我所問的。爲了能夠在'string'上使用'is'運算符。所以我想最好的方法是將這個'string'轉換爲'class' ......但不知道如何。 –

+0

你不能用is來表示一個字符串,所以如果這就是你想要做的,放棄 –

回答

4

您可以驗證使用ClassName財產

page.Controls[0].ClassName = mystr 

但請注意,這不會完成與is運算符完全相同的操作。要看到不同之處,假設您有一個類TFruit和一個子類TApple。如果myFruitTApple的實例,則myFruit is TApplemyFruit is TFruit將產生true。但是,當然,ClassName仍然只是TApple

如果需要is運營商的全部功能,您可以通過HVD利用ClassParent財產,爲suggested

function IsDerivedFrom(AClass: TClass; const AClassName: string): boolean; 
begin 
    if not Assigned(AClass) then Exit(false); 
    result := SameText(AClass.ClassName, AClassName) or 
    IsDerivedFrom(AClass.ClassParent, AClassName); 
end; 

要獲得類的對象,請使用ClassType屬性:

IsDerivedFrom(page.Controls[0].ClassType, mystr); 
+1

這和'is'不一樣。 'page.Controls [0]是TControl'會評估爲true,但是'page.Controls [0] .ClassName ='TControl''會評估爲false。 – hvd

+0

@hvd真的...它不工作...所以有其他想法? –

+0

@FlashThunder如果您有完全匹配,它只會評估爲true。如果你得到的對象派生自你正在檢查的類型,'is'也會返回true。 – hvd

1

對於問題主體中的具體情況,Andreas Rejbrand(在hvd的協助下)的回答是一個很好的答案。但是,對於問題標題所隱含的更廣泛的問題 - 如何將包含類名的字符串轉換爲類引用? - 你可以在Delphi中的一個新的(ISH)版本使用擴展RTTI:

unit ClassLookupUtils; 

interface 

uses 
    System.SysUtils, System.Generics.Collections, System.Rtti; 

type 
    RttiClassLookup = record 
    strict private 
    class var FMap: TDictionary<string, TClass>; 
    class destructor Destroy; 
    public 
    class function Find(const ClassName: string): TClass; static; 
    end; 

implementation 

class destructor RttiClassLookup.Destroy; 
begin 
    FMap.Free; 
end; 

class function RttiClassLookup.Find(const ClassName: string): TClass; 
var 
    RttiType: TRttiType; 
    RttiContext: TRttiContext; 
begin 
    if FMap = nil then 
    begin 
    FMap := TDictionary<string, TClass>.Create; 
    for RttiType in RttiContext.GetTypes do 
     if RttiType is TRttiInstanceType then 
     FMap.AddOrSetValue(RttiType.Name.ToLowerInvariant, (RttiType as TRttiInstanceType).MetaclassType); 
    end; 
    if not FMap.TryGetValue(ClassName.ToLowerInvariant, Result) then 
    Result := nil; 
end; 

end. 

在使用中:

var 
    MyStr: string; 
    MyStrClass: TClass; 
begin 
    //... 
    MyStrClass := RttiClassLookup.Find(MyStr); 
    if MyStrClass <> nil then 
    for I := 0 to Page.ControlCount - 1 do 
     if Page.Controls[I].InheritsFrom(MyStrClass) then 
     begin 
     //... 
     end; 

這裏的背景是SomeObj is SomeClass作爲(SomeObj <> nil) and SomeObj.InheritsFrom(SomeClass)實施。

+0

RTTI讓你創建自己的字典?哎喲。偉大的代碼,我認爲這確實回答了原來的問題。 – alcalde

+0

TRttiContext有一個FindType方法,但需要傳遞給它的完全限定名(例如'Vcl.StdCtrls.TGroupBox'),並且OP希望使用非限定名。 –

3

您正在尋找的功能是位於System.Classes中的GetClass。請注意,班級必須註冊。

System.Classes.GetClass

0

你必須從@UweRaabe使用RTTI獲得ClassName一個很好的答案。

一個簡單的(不是很強大的)hack而不使用RTTI就是使用TComponent。Name屬性,它是一個字符串,像這樣 - 沒有is操作:

If (pos('GroupBox', page.Controls[0].name)>0) then ... 

默認情況下,控制得到了相同的名稱作爲實例變量,所以GroupBox1.name='GroupBox1」。您可以更改數據庫條目以使用substr'groupbox'或從數據庫中的類型名稱字符串中提取'groupbox'。這就是說,如果您繼承了這種設計方法,即將類型名稱作爲字符串保存在數據庫中,然後在運行時使用它們來檢查不同組件的類型,那麼您就會被卡住,所以它。但是Delphi是一種強類型的編譯語言,因此將類型名稱作爲數據庫中的字符串持久存儲,並在運行時讀取它們並將它們解碼爲Delphi類型並不會「正確地識別」IMO。如果可能的話,我會重新考慮這個設計。考慮在Delphi中使用classOf類型,枚舉等來完成所有操作。