[英]Delphi - how to enum string to type
我在数据库中找到了类似“ TGroupBox”或“ TEdit”的字符串……现在我需要根据它们检查元素……如何枚举要键入的字符串?
我的意思是这样的:
mystr := 'TGroupBox';
If (page.Controls[0] is mystr) then ...
当然它不会起作用,因为会出现错误:
E2015运算符不适用于此操作数类型
我该怎么做呢?
您可以验证
page.Controls[0].ClassName = mystr
使用ClassName
属性。
但是请注意,这与is
运算符的功能并不完全相同。 要查看区别,假设您有一个TFruit
类和一个TApple
子类。 如果myFruit
是一个实例TApple
,那么这两个myFruit is TApple
和myFruit is TFruit
将产生true
。 但是,当然, ClassName
仍然只是TApple
。
如果需要is
运算符的全部功能, is
可以使用ClassParent
建议的ClassParent
属性:
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);
您要查找的函数是System.Classes中的GetClass
。 请注意,必须注册该课程。
对于问题正文中的特定情况,Andreas Rejbrand(在hvd的协助下)的回答是一个很好的答案。 但是,对于问题标题所隐含的更广泛的问题-如何将包含类名的字符串转换为类引用? -您可以在新版本的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)
。
您可以使用RTTI
从@UweRaabe获得很好的答案,以获取ClassName
。
一个不使用RTTI的简单(但不是很健壮)的方法是使用TComponent.Name属性,它是一个字符串,像这样-没有is
运算符:
If (pos('GroupBox', page.Controls[0].name)>0 ) then ...
默认情况下,控件的名称与实例变量的名称相同,因此GroupBox1.name='GroupBox1
'。 您可以更改数据库条目以使用substr'groupbox'或从数据库的类型名称字符串中提取'groupbox'。
话虽这么说,如果您继承了将类型名称作为字符串持久存储在数据库中,然后在运行时使用它们来检查不同组件的类型的设计方法,那么您就一定会坚持下去。 但是Delphi是一种强类型化的编译语言,因此将类型名称作为字符串保留在数据库中,并在运行时读取它们并将其解码为Delphi类型,只是IMO并不“正确”。 如果可能的话,我会重新考虑这个设计。 考虑使用classOf
类型,枚举等在Delphi中完成所有操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.