使用RTTI获取静态数组的记录字段类型失败

8

我想获取记录字段的类型,以创建正确的比较器(作为任何/几乎任何记录类型的通用解决方案)。 我找不到静态数组的类型信息:

  TArrFieldTest = record
    a: string;
    b: array[0..3] of byte;
  end;

procedure Test;
var
  rttiContext: TRttiContext;
  rttiType: TRttiType;
  rttiFields: TArray<TRttiField>;
begin
  rttiType := rttiContext.GetType(TypeInfo(TArrFieldTest));
  rttiFields := rttiType.GetFields;
  Assert(rttiFields[0].FieldType<>nil); // it's ok
  Assert(rttiFields[1].FieldType<>nil); // fail here!
end;

静态数组的FieldType为零。 这里有什么问题吗? 或者,也许有更简单的方法创建记录比较器,可用于TArray/TDictionary等?


同样适用于ShortString类型(David Heffernan的解决方案也适用于它们)。 - John B. Lambe
1个回答

11

为了使用运行时类型信息(RTTI),您需要声明一个类型。例如:

type
  TMyStaticArrayOfByte = array[0..3] of byte;

  TArrFieldTest = record
    a: string;
    b: TMyStaticArrayOfByte;
  end;

动态数组的信息可以在不声明单独类型的情况下获得。对于静态数组,我们必须声明单独的类型,这是唯一的方法吗?虽然不如我预期的好,但总比没有强,谢谢! - Andrei Galatyn
4
动态数组是编译器管理的类型,具有自己的运行时类型信息(RTTI),其中包含了具有各自RTTI的不同类型元素,并且动态数组的RTTI链接到这些元素的RTTI。静态数组不是一种类型,因此没有RTTI,除非你将其定义为一种类型,否则它只是一块内存。 - Remy Lebeau
如果我没记错的话,如果你要使用 RTTI 访问数组项,你还需要声明范围为 MyStaticArrayOfByteRange = 0..3; - LU RD
@Remy 我的意思是普通动态数组(不是变体),它们始终具有相同类型的所有元素(“TArray <T>”或“T的数组”)。你解释了一些内部细节,很好,但我认为“a:array [0..0] of byte”和“a:array of byte”只是不同的声明类型的方式。它们都是类型定义,我无法想象为什么Delphi只支持其中之一。这限制了编写流等通用解决方案的能力。托管类型在这里不是边界,大多数非托管类型都得到了支持,但静态数组没有得到支持。 - Andrei Galatyn
小更新:对于托管类型的静态数组(“array [0..1] of string”),可以检索RTTI。 - Andrei Galatyn
@AndreiGalatyn:"我的意思是普通动态数组(而不是变体)" - 我也是这个意思。显式声明的动态数组类型具有其自己的RTTI,其中包含对元素类型的RTTI(如果有)。 "我认为a: array[0..0] of bytea: array of byte只是声明类型的不同方式" - 在那种情况下,a并未引用某种类型,它只是一个内存块。 Byte 可能有自己的RTTI,但 a: array[0..0] of Bytea: array of Byte 并没有 a 的 RTTI,因为 a 并未引用特定的类型,但是 TA = array of Byte; a: TA 则有。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接