[英]Delphi - how to enum string to type
I got strings in database like 'TGroupBox' or 'TEdit' ... now I need to check element against them... how do I enumerate string to type? 我在数据库中找到了类似“ TGroupBox”或“ TEdit”的字符串……现在我需要根据它们检查元素……如何枚举要键入的字符串?
I mean something like this: 我的意思是这样的:
mystr := 'TGroupBox';
If (page.Controls[0] is mystr) then ...
Of course it won't work, as error appears: 当然它不会起作用,因为会出现错误:
E2015 Operator not applicable to this operand type
E2015运算符不适用于此操作数类型
How do I do that correctly? 我该怎么做呢?
You can verify that 您可以验证
page.Controls[0].ClassName = mystr
using the ClassName
property. 使用
ClassName
属性。
But notice that this doesn't do exactly the same thing as the is
operator. 但是请注意,这与
is
运算符的功能并不完全相同。 To see the difference, suppose you have a class TFruit
and a subclass TApple
. 要查看区别,假设您有一个
TFruit
类和一个TApple
子类。 If myFruit
is an instance of a TApple
, then both myFruit is TApple
and myFruit is TFruit
will yield true
. 如果
myFruit
是一个实例TApple
,那么这两个myFruit is TApple
和myFruit is TFruit
将产生true
。 But of course, the ClassName
will still only be TApple
. 但是,当然,
ClassName
仍然只是TApple
。
If you need the full functionality of the is
operator, you can make use of the ClassParent
property, as suggested by hvd: 如果需要
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;
To get the class of an object, use the ClassType
property: 要获取对象的类,请使用
ClassType
属性:
IsDerivedFrom(page.Controls[0].ClassType, mystr);
The function you are looking for is GetClass
located in System.Classes. 您要查找的函数是System.Classes中的
GetClass
。 Be aware that the class has to be registered. 请注意,必须注册该课程。
For the specific scenario in the question body the answer by Andreas Rejbrand (with assistance from hvd) is a good one. 对于问题正文中的特定情况,Andreas Rejbrand(在hvd的协助下)的回答是一个很好的答案。 However, for the broader problem implied by the question title - how to I convert a string containing a class name to a class reference?
但是,对于问题标题所隐含的更广泛的问题-如何将包含类名的字符串转换为类引用? - you can utilise extended RTTI in a new(ish) version of Delphi:
-您可以在新版本的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.
In use: 正在使用:
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;
The background here is that SomeObj is SomeClass
is implemented as (SomeObj <> nil) and SomeObj.InheritsFrom(SomeClass)
. 这里的背景是
SomeObj is SomeClass
被实现为(SomeObj <> nil) and SomeObj.InheritsFrom(SomeClass)
。
You have a good answer from @UweRaabe using RTTI
to get ClassName
. 您可以使用
RTTI
从@UweRaabe获得很好的答案,以获取ClassName
。
A simple (and not very robust) hack without using RTTI would be to use the TComponent.Name property, which is a string, like this - without the is
operator: 一个不使用RTTI的简单(但不是很健壮)的方法是使用TComponent.Name属性,它是一个字符串,像这样-没有
is
运算符:
If (pos('GroupBox', page.Controls[0].name)>0 ) then ...
By default, a control gets the same name as the instance variable, so GroupBox1.name='GroupBox1
'. 默认情况下,控件的名称与实例变量的名称相同,因此
GroupBox1.name='GroupBox1
'。 You can either change your database entries to use the substr 'groupbox' or extract 'groupbox' from the type name string in your database. 您可以更改数据库条目以使用substr'groupbox'或从数据库的类型名称字符串中提取'groupbox'。
That being said, if you've inherited this design approach of persisting type names as strings in a database and then using them at runtime to check the types of different components, then you're stuck with it, and so be it. 话虽这么说,如果您继承了将类型名称作为字符串持久存储在数据库中,然后在运行时使用它们来检查不同组件的类型的设计方法,那么您就一定会坚持下去。 But Delphi is a strongly typed, compiled language, so persisting type names as strings in a database and reading them at runtime and decoding them into Delphi types just doesn't "smell right" IMO.
但是Delphi是一种强类型化的编译语言,因此将类型名称作为字符串保留在数据库中,并在运行时读取它们并将其解码为Delphi类型,只是IMO并不“正确”。 I would re-think this design if possible.
如果可能的话,我会重新考虑这个设计。 Consider doing it all in Delphi using
classOf
type, enumerations, etc. 考虑使用
classOf
类型,枚举等在Delphi中完成所有操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.