Delphi - 如何枚举字符串以进行输入

时间:2014-05-10 15:48:10

标签: delphi

我在数据库中得到了像' TGroupBox'或者' TEdit' ...现在我需要检查元素对...他们如何枚举要输入的字符串?

我的意思是这样的:

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

当然,由于出现错误,它无法正常工作:

  

E2015运算符不适用于此操作数类型

我该如何正确地做到这一点?

4 个答案:

答案 0 :(得分:4)

您可以验证

page.Controls[0].ClassName = mystr

使用ClassName属性。

但请注意,这与is运算符完全不同。要查看差异,假设您有一个类TFruit和一个子类TApple。如果myFruitTApple的实例,则myFruit is TApplemyFruit 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中。请注意,必须注册课程。

System.Classes.GetClass

答案 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中完成所有操作。