我在数据库中得到了像' TGroupBox'或者' TEdit' ...现在我需要检查元素对...他们如何枚举要输入的字符串?
我的意思是这样的:
mystr := 'TGroupBox';
If (page.Controls[0] is mystr) then ...
当然,由于出现错误,它无法正常工作:
E2015运算符不适用于此操作数类型
我该如何正确地做到这一点?
答案 0 :(得分:4)
您可以验证
page.Controls[0].ClassName = mystr
使用ClassName
属性。
但请注意,这与is
运算符完全不同。要查看差异,假设您有一个类TFruit
和一个子类TApple
。如果myFruit
是TApple
的实例,则myFruit is TApple
和myFruit is TFruit
都会产生true
。但当然,ClassName
仍然只是TApple
。
如果您需要is
运算符的完整功能,则可以使用h {ClassParent
suggested作为ClassType
属性。
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;
要获取对象的类,请使用{{3}}属性:
IsDerivedFrom(page.Controls[0].ClassType, mystr);
答案 1 :(得分:3)
您要查找的功能是GetClass
位于System.Classes中。请注意,必须注册课程。
答案 2 :(得分:1)
对于问题机构中的特定场景,Andreas Rejbrand的答案(在hvd的帮助下)是一个很好的答案。但是,对于问题标题隐含的更广泛的问题 - 如何将包含类名的字符串转换为类引用? - 您可以在新的(ish)版本的Delphi中使用扩展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)
。
答案 3 :(得分:0)
@UweRaabe使用RTTI
得到ClassName
给出了一个很好的答案。
不使用RTTI的简单(并且不是非常强大)hack将使用TComponent.Name属性,这是一个字符串,如下所示 - 没有is
运算符:
If (pos('GroupBox', page.Controls[0].name)>0 ) then ...
默认情况下,控件的名称与实例变量的名称相同,因此GroupBox1.name='GroupBox1
'。您可以更改数据库条目以使用子组'groupbox'或从数据库中的类型名称字符串中提取'groupbox'。
话虽如此,如果你继承了这种设计方法,即在数据库中将类型名称持久化为字符串,然后在运行时使用它们来检查不同组件的类型,那么你就会坚持下去,所以就这样吧。但是Delphi是一种强类型的编译语言,所以将类型名称作为字符串保存在数据库中并在运行时读取它们并将它们解码为Delphi类型只是“气味正确”IMO。如果可能的话,我会重新考虑这个设计。考虑使用classOf
类型,枚举等在Delphi中完成所有操作。