简体   繁体   English

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

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

System.Classes.GetClass System.Classes.GetClass

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.

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