如何测试未知的 Delphi RTTI TValue 是否反映任何类型的通用 TList<>(或至少 TEnumerable<>)的对象?

2023-12-03

在德尔福,如果我有一个TValue反映未知对象的实例,如何测试该对象是否是任何类型泛型的实例TEnumerable<>(或者甚至更好,也which它是特定通用枚举类型的实例,例如TList<>)?

注意:我已经知道如何轻松检查其exact类型,即与.BaseType对应的属性TRttiType of the TValue,例如导致TList<string>,但我想测试的是它是否是TList<> of any子项类型.

为了举例说明这个假设代码“IsAnyKindOfGenericEnumerable()”的工作原理,下面是一些示例代码:

var
   LContext : TRttiContext;
   obj_1_rtti_value : TValue;
   obj_2_rtti_value : TValue;
   obj_3_rtti_value : TValue;
   obj_1_rtti_type : TRttiType;
   obj_2_rtti_type : TRttiType;
   obj_3_rtti_type : TRttiType;

LContext := TRttiContext.Create();

{
...
obj_1_rtti_value is set to a TValue reflection of a TList<string> object here
obj_2_rtti_value is set to a TValue reflection of a plain TObject object here
obj_3_rtti_value is set to a TValue reflection of a TQueue<integer> object here
...
}

obj_1_rtti_type := LContext.GetType(obj_1_rtti_value.TypeInfo);
obj_2_rtti_type := LContext.GetType(obj_2_rtti_value.TypeInfo);
obj_3_rtti_type := LContext.GetType(obj_3_rtti_value.TypeInfo);

IsAnyKindOfGenericEnumerable(obj_1_rtti_type); //Would return true
IsAnyKindOfGenericEnumerable(obj_2_rtti_type); //Would return false
IsAnyKindOfGenericEnumerable(obj_3_rtti_type); //Would return true

再说一次,最好的事情是如果我也能检测到which有点儿TEnumerable<>输入它,例如:

IsAnyKindOfGenericEnumerable(obj_1_rtti_type); //Will return true + `TList<>`
IsAnyKindOfGenericEnumerable(obj_2_rtti_type); //Will return false
IsAnyKindOfGenericEnumerable(obj_3_rtti_type); //Will return true + `TQueue<>`

我努力了:

if obj_1_rtti_type is TRttiEnumerationType then
begin
   //...
end;

但由于某种原因,这评估为false,我完全不知道这是为什么?表达方式value_type.BaseType.Name确实评估为'TEnumerable<System.string>'在这种情况下,但为了实现我的目标,除了手动解析该字符串之外,确实必须有其他方法,对吧?

最后,必须仅使用 RTTI 信息来实现目标,即不允许通过引用 TValue 背后的真实对象进行任何“作弊”(出于本问题范围之外的原因)。


没有为通用类型本身生成 RTTI(它们在运行时不存在),并且每个特定实例化(例如TList<string>) is a 具有自己独特 RTTI 的不同类类型。你必须检查每个单独的类型,无法测试任何通用类型。解析类名是检测泛型类型的唯一方法。

  1. use TRttiType.Name获取字符串形式的类名 ('TList<System.string>').

  2. 解析它以检测是否存在尖括号('<>').

  3. 提取括号之间的子字符串 ('System.string')

  4. 沿着祖先树行走,寻找其祖先TRttiType.Name is 'TEnumerable<...>', where ...是提取的子字符串('TEnumerable<System.string>').

但是,这种方法对于派生自的类类型失败TEnumerable<T>但本身没有泛型参数,例如:

type
  TMyClass = class(TEnumerable<string>)
  end;

为了解决这个问题,请忽略步骤 1-3 并直接直接跳到步骤 4,忽略括号之间出现的任何值,例如:

function IsAnyKindOfGenericEnumerable(AType: TRttiType): Boolean;
begin
  Result := False;
  while AType <> nil do
  begin
    Result := StartsText('TEnumerable<', AType.Name);
    if Result then Exit;
    AType := AType.BaseType;
  end;
end;

As for TRttiEnumerationType, 它代表枚举类型 (ie: type typeName = (val1, ...,valn);)。与以下无关TEnumerable<T>。这就是为什么is运算符始终为您返回 False - 您正在测试的 RTTI 类型都不代表枚举。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何测试未知的 Delphi RTTI TValue 是否反映任何类型的通用 TList<>(或至少 TEnumerable<>)的对象? 的相关文章

  • 新编译的应用程序需要 UAC/elevation?

    我有一个系统 我将其设置为普通的 UAC 并在我的 delphi 环境中编译名为 ka exe 的项目 并为其创建一个 installshield 项目 设置完毕 一切顺利 但每当我开始我的程序时 它都需要提升 而我不知道为什么 为了确保
  • 如何从窗体单元外部访问delphi控件?

    我试图从如下定义的过程中调用计时器的 Enabled 属性 procedure Slide Form TForm Show Boolean 并且没有固定的形式名称 例如 Form2 Timer 将表单的单位放入使用列表后 这可以工作 For
  • 返回具有关联类型的特征

    struct A struct PropA struct B struct PropB trait AB type prop fn a self gt fn b self p Self prop gt impl AB for A type
  • 从不同的形式调用过程

    我正在使用 Lazarus 我有一个名为TForm1单元名称为 Unit 1 在这里我有一个名为mergeDATfile a shortint 这会产生一些东西 顺便说一句 我必须创建另一个名为TForm2里面有按钮 Button1 当它被
  • Firebird 或 NexusDB

    我知道有很多与 Delphi 数据库相关的问题 但我只考虑这两个数据库 我需要查询大约 100 000 条记录 根据您的经验 哪个更快 作为嵌入式 as C S Thanks 我还没用过 Nexus tbh 但我经常使用 Firebird
  • 让线程在窗体关闭时保持运行

    我在我的应用程序上创建了一个同步线程 我想知道如果我关闭申请表 是否有办法让该线程保持打开状态 直到完成同步过程 调用线程的WaitFor方法在您的 DPR 文件中 之后Application Run线 如果线程已经运行完毕 那么WaitF
  • Spring MVC:通用 DAO 和服务类

    我正在 Spring MVC 中编写网页 我使用 Generic DAO 编写了所有 DAO 现在我想重写我的服务类 我该如何写 通用服务 我的 DAO 如下 DAO package net example com dao import j
  • 不兼容的类型:Class 无法转换为 Class,其中 CAP#1 是新类型变量

    当我编写一些代码时 我遇到了一些让我烦恼的事情 我在下面的代码示例中收集了两个示例 The cls1行使用 lambda 表达式但不编译 而cls2行使用方法引用并编译 我知道 如果我使用非泛型对象 那么那里没有问题 但在这里 我使用泛型
  • 在该对象调用的事件期间销毁该对象

    我有一个按钮 它的 OnClick 事件调用一个销毁按钮的过程 但随后 线程 想要返回到 OnClick 事件 并且我遇到了访问冲突 我完全被难住了 您需要在按钮的所有代码执行完毕后销毁该按钮 执行此操作的标准方法是将用户定义的消息发布到表
  • 指针^ 与 s[1]

    在读取数据的函数中 数据含义只字符串 从磁盘 我应该更喜欢哪个 哪个更好 A DiskStream Read Pointer s Count or B DiskStream Read s 1 Count Note 我知道两者都有相同的结果
  • 如果需要函数类型作为类型参数,如何输入 None?

    假设我有一个需要回调的函数 fn foo
  • Proguard 正在破坏我的清洁度。 Gson 和泛型

    我有一个从持久性加载信息的函数 我只是以一种非常简单的方式告诉它的类型 该类称为SharedPreferencesHelper kt所以它是一个真正的生活问题解决者 fun
  • 如何为每个线程自动全局初始化/取消初始化某些内容?

    我有一个单位initialization and finalization部分 该单元包含一个复杂的对象 该对象在initialization并毁于finalization 但是 该对象还包含一个 ADO 连接 这使得跨线程使用它时出现问题
  • .Equals 上的 C# 泛型方法中的意外行为

    为什么 Equals 方法返回与泛型方法不同的结果 我认为这里有一些我不明白的自动拳击 下面是使用 net 3 5 或 4 0 重现该行为的示例 static void Main string args TimeZoneInfo tzOne
  • delphi专家中的第三方依赖

    我正在编写一个delphi ide Expert 带有一些第三方依赖项 视觉控件 我的问题是当这个专家将安装在目标机器上时 这台电脑是否也需要安装这些第三方组件 或者组件是embeded在生成的 bpl 内部 它们将依赖于您放置在包的 re
  • SSL 错误 1409442E 使用 TIdHTTP 通过 HTTPS 下载文件 [重复]

    这个问题在这里已经有答案了 我正在使用德尔福10 3 3 下面的代码曾经有效 但现在尝试通过 HTTPS 下载文件时遇到错误 连接 SSL 错误错误 1409442E SSL 例程 SSL3 READ BYTES tlsv1 警报协议版本
  • 如何获取属于某个进程的打开句柄的计数?

    您可以使用该程序流程浏览器 http technet microsoft com en us sysinternals bb896653查看正在运行的应用程序有多少个句柄 有没有办法用Delphi代码来获取这个数字 我有兴趣跟踪应用程序本身
  • 在 Java 类型参数中, 仅意味着严格的子类型?或者 E 也足够了吗?

    在 Java 类型参数中 是否仅意味着严格的子类型 或者 E 也足够了吗 这并不严格 E就足够了
  • 如何等到我启动的程序使用完该文件后才删除该文件?

    我一直在寻找一种方法来打开通过 Delphi 应用程序及其适当的应用程序保存到我的计算机上的文件 该文件存储在 SQL 数据库中的 Varbinary 字段中 加载到内存流中 然后通过 TMemoryStream 的 SavetoFile
  • Java 泛型/类型调度问题

    考虑以下程序 import java util List import java util ArrayList public class TypeTest public static class TypeTestA extends Type

随机推荐