繁体   English   中英

Delphi-如何枚举要键入的字符串

[英]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 TApplemyFruit 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 请注意,必须注册该课程。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM