【问题标题】:Delphi - how to enum string to typeDelphi - 如何枚举字符串以输入
【发布时间】:2014-05-10 15:48:10
【问题描述】:

我在数据库中有字符串,例如“TGroupBox”或“TEdit”……现在我需要对照它们检查元素……如何枚举要键入的字符串?

我的意思是这样的:

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

当然不行,出现错误:

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

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

【问题讨论】:

  • 你真正想要完成什么?
  • 我实际上是在按照我的要求去做。能够在string 上使用is 运算符。所以我想最好的方法是将 string 转换为 class... 但不知道如何。
  • 你不能用 is 和一个字符串,所以如果你想这样做,放弃
  • 这真的是一个糟糕的问题吗?按照我的阅读方式,OP 想使用 is 关键字,但知道她不能,因为她没有类,而是一个带有类名的字符串。
  • @AndreasRejbrand - 确实。

标签: delphi


【解决方案1】:

你可以验证

page.Controls[0].ClassName = mystr

使用ClassName 属性。

但请注意,这与is 运算符的作用并不完全相同。要查看差异,假设您有一个类TFruit 和一个子类TApple。如果myFruitTApple 的一个实例,那么myFruit is TApplemyFruit is TFruit 都将产生true。但当然,ClassName 仍然只是TApple

如果您需要is 运算符的全部功能,您可以使用ClassParent 属性,如hvd 的suggested

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);

【讨论】:

  • 这与is 不同。 page.Controls[0] is TControl 将评估为真,但page.Controls[0].ClassName = 'TControl' 将评估为假。
  • @FlashThunder 仅当您有完全匹配时才会评估为真。 is 如果你得到的对象是从你正在检查的类型派生的,也会返回 true。
  • 啊 nvm... 它工作正常。我不明白你的评论,但现在我明白了……完全匹配就可以了。但是如果有人知道如何做到这一点,更多is 方式会很棒......
  • @FlashThunder 是的,在这种情况下,一个简单的字符串比较就可以了,但是无论如何要回答你的问题,如果你也需要检查基本类型,你可以编写一个递归函数IsDerivedFrom(c: TClass; const name: string),它首先检查是否完全匹配,如果失败,则调用IsDerivedFrom(c.ClassParent, name)。您可以将其称为IsDerivedFrom(obj.ClassType, mystr)。我会让安德烈亚斯把它放在这个答案中(如果需要的话),或者我可以稍后将它作为单独的答案发布。
  • @hvd 没有办法简单地将字符串枚举到类?
【解决方案2】:

您要查找的函数是位于 System.Classes 中的GetClass。请注意,必须注册该类。

System.Classes.GetClass

【讨论】:

    【解决方案3】:

    对于问题正文中的特定场景,Andreas Rejbrand(在 hvd 的帮助下)的答案是一个很好的答案。但是,对于问题标题所暗示的更广泛的问题 - 如何将包含类名的字符串转换为类引用? - 您可以在 Delphi 的新(ish)版本中使用扩展 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 &lt;&gt; nil) and SomeObj.InheritsFrom(SomeClass)

    【讨论】:

    • RTTI 让您创建自己的字典?哎哟。很棒的代码,我认为这确实回答了最初的问题。
    • TRttiContext 有一个 FindType 方法,但是这需要传递给它的完全限定名称(例如 'Vcl.StdCtrls.TGroupBox')并且 OP 希望使用非限定名称。
    【解决方案4】:

    @UweRaabe 使用RTTIto getClassName 给出了很好的答案。

    不使用 RTTI 的简单(但不是很健壮)的破解方法是使用 TComponent.Name 属性,它是一个字符串,就像这样 - 没有 is 运算符:

     If (pos('GroupBox', page.Controls[0].name)>0 ) then ...
    

    默认情况下,控件与实例变量具有相同的名称,即GroupBox1.name='GroupBox1'。您可以更改数据库条目以使用 substr 'groupbox' 或从数据库中的类型名称字符串中提取 'groupbox'。

    话虽如此,如果您继承了这种将类型名称作为字符串持久保存在数据库中的设计方法,然后在运行时使用它们来检查不同组件的类型,那么您就会被它困住,就这样吧.但是 Delphi 是一种强类型的编译语言,因此将类型名称作为字符串保存在数据库中并在运行时读取它们并将它们解码为 Delphi 类型只是不会“闻起来”IMO。如果可能的话,我会重新考虑这个设计。考虑使用 classOf 类型、枚举等在 Delphi 中完成所有操作。

    【讨论】:

      猜你喜欢
      • 2014-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      相关资源
      最近更新 更多